One of my small projects (10 Years Later, Only 250 SLOC) is a mostly static website generated by some backend programs. (Some of the UI is JavaScript, but it's all data-driven.)

I've spent plenty of time tweaking the page generation, and as such I need to know how things look after running through all of the data-driven templates. While I could deploy to a live web server after running the "Regenerate the desired pages" program, I pulled out the Plack hammer.

Remember how stupidly simple Plack is? A Plack application is just a function. Plack comes with some demonstration applications which are a page or two of code apiece—including the almost exactly right Plack::App::File. You can even run it as a Plack one-liner.

I wanted something a little more: a program I could run with a single argument, the name of the directory root from which to serve files. Something like:

$ plackfile . $ plackfile root/static/

... would do. This took only a few lines of code:

#!/usr/bin/env perl use Plack::Runner; my $app = Plack::App::IndexFile->new({ root => shift })->to_app; my $runner = Plack::Runner->new; $runner->parse_options( '--access-log' => '/dev/null', @ARGV ); $runner->run( $app ); package Plack::App::IndexFile; use parent 'Plack::App::File'; sub locate_file { my ($self, $env) = @_; my $path = $env->{PATH_INFO} || ''; return $self->SUPER::locate_file( $env ) unless $path && $path =~ m{/$}; $env->{PATH_INFO} .= 'index.html'; return $self->SUPER::locate_file( $env ); }

Plack::Runner is the module at the core of plackup , and Plack::App::File is a Plack core application which serves static files beneath a root directory.

Unfortunately, Plack::App::File doesn't default to index.html when the user requests a directory, so I had to override its locate_file() method to add this behavior. It's a touch fragile, as a better approach would be to let P::A::F take an extra optional coderef constructor parameter to use as a last resort when the user has requested a directory. Still, this works.

The only other interesting part of this code is the argument handling. Plack::Runner takes the same arguments as the plackup file, but this code defaults to redirecting the access log normally printed to STDOUT to /dev/null. This is quieter, which matches my normal purposes, but it's overrideable if necessary.

Two minutes of work on my part (plus 10 writing this post) will save me a tremendous amount of time. Hopefully it will do the same for you.