1package Plack::Middleware::File::Sass; 2 3use strict; 4use 5.008_001; 5our $VERSION = '0.03'; 6 7use parent qw(Plack::Middleware); 8use Plack::Util::Accessor qw(sass syntax); 9use Plack::Util; 10use IPC::Open3 qw(open3); 11use Carp (); 12 13my $text_sass; 14my %valid = (sass => 1, scss => 1); 15 16sub prepare_app { 17 my $self = shift; 18 19 $self->syntax("sass") unless defined $self->syntax; 20 $valid{$self->syntax} or Carp::croak("Unsupported syntax: ", $self->syntax); 21 22 my $sass = `sass -v`; 23 if ($sass && $sass =~ /Sass 3/) { 24 $self->sass(\&sass_command); 25 } elsif (eval { require Text::Sass }) { 26 $self->sass(\&sass_perl); 27 } else { 28 Carp::croak("Can't find sass gem nor Text::Sass module"); 29 } 30} 31 32sub sass_command { 33 my($syntax, $body) = @_; 34 35 my $pid = open3(my $in, my $out, my $err, 36 "sass", "--stdin", ($syntax eq 'scss' ? '--scss' : ())); 37 print $in $body; 38 close $in; 39 40 my $buf = join '', <$out>; 41 waitpid $pid, 0; 42 43 return $buf; 44} 45 46sub sass_perl { 47 my($syntax, $body) = @_; 48 49 my $method = "${syntax}2css"; 50 $text_sass ||= Text::Sass->new; 51 $text_sass->$method($body); 52} 53 54sub call { 55 my($self, $env) = @_; 56 57 my $syntax = $self->syntax; 58 59 # Sort of depends on how App::File works 60 my $orig_path_info = $env->{PATH_INFO}; 61 if ($env->{PATH_INFO} =~ s/\.css$/.$syntax/i) { 62 my $res = $self->app->($env); 63 64 return $res unless ref $res eq 'ARRAY'; 65 66 if ($res->[0] == 200) { 67 my $sass; Plack::Util::foreach($res->[2], sub { $sass .= $_[0] }); 68 my $css = $self->sass->($syntax, $sass); 69 70 my $h = Plack::Util::headers($res->[1]); 71 $h->set('Content-Type' => 'text/css'); 72 $h->set('Content-Length' => length $css); 73 74 $res->[2] = [ $css ]; 75 } elsif ($res->[0] == 404) { 76 $env->{PATH_INFO} = $orig_path_info; 77 $res = $self->app->($env); 78 } 79 80 return $res; 81 } 82 83 return $self->app->($env); 84} 85 861; 87__END__ 88 89=encoding utf-8 90 91=for stopwords 92 93=head1 NAME 94 95Plack::Middleware::File::Sass - Sass and SCSS support for all Plack frameworks 96 97=head1 SYNOPSIS 98 99 use Plack::App::File; 100 use Plack::Builder; 101 102 builder { 103 mount "/stylesheets" => builder { 104 enable "File::Sass"; 105 Plack::App::File->new(root => "./stylesheets"); 106 }; 107 }; 108 109 # Or with Middleware::Static 110 enable "File::Sass", syntax => "scss"; 111 enable "Static", path => qr/\.css$/, root => "./static"; 112 113=head1 DESCRIPTION 114 115Plack::Middleware::File::Sass is a Plack middleware component that 116works with L<Plack::App::File> or L<Plack::Middleware::Static> to 117compile L<Sass|http://sass-lang.com/> templates into CSS stylesheet in 118every request. 119 120When a request comes in for I<.css> file, this middleware changes the 121internal path to I<.sass> or I<.scss>, depending on the configuration, 122in the same directory. If the Sass template is found, a new CSS 123stylesheet is built on memory and served to the browsers. Otherwise, 124it falls back to the original I<.css> file in the directory. 125 126This middleware should be very handy for the development. While Sass 127to CSS rendering is reasonably fast, for the production environment 128you might want to precompile Sass templates to CSS files on disk and 129serves them with a real web server like nginx or lighttpd. 130 131=head1 SASS BACKENDS 132 133If you have the sass gem version higher than 3 installed and have the 134C<sass> executable available in your PATH, this module automatically 135uses the command to convert Sass or SCSS into CSS. If the command is 136not available and you have L<Text::Sass> perl module available, it 137will be used. Otherwise you'll get an exception during the 138initialization of this middleware component. 139 140=head1 OPTIONS 141 142=over 4 143 144=item syntax 145 146Defines which syntax to use. Valid values are I<sass> and 147I<scss>. Defaults to I<sass>. 148 149=back 150 151=head1 AUTHOR 152 153Tatsuhiko Miyagawa E<lt>miyagawa@bulknews.netE<gt> 154 155=head1 LICENSE 156 157This library is free software; you can redistribute it and/or modify 158it under the same terms as Perl itself. 159 160=head1 SEE ALSO 161 162L<Plack::App::File> L<Text::Sass> L<http://sass-lang.com/> 163 164=cut 165