Serving a Local Directory with Plack


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.


This is really nifty and i can't remember how often i hacked together something stupid for such a purpose.

Two things to note:

The Plack::App::File link is broken.

Are you intending to submit a pull req to Plack::App::File? :)

Looks like you've re-implemented weborf in Plack :)

Very fun and useful!

I played with Plack::File::Directory too, making a fake cherokee static file server in front of it.

It looks better than the original, and is definitely more perlish ;-) .

Modern Perl: The Book

cover image for Modern Perl: the book

The best Perl Programmers read Modern Perl: The Book.

sponsored by the How to Make a Smoothie guide



About this Entry

This page contains a single entry by chromatic published on August 24, 2011 6:15 PM.

No Policy Can Save Wrong Code was the previous entry in this blog.

Why My Side Project Doesn't Use Perl 6 is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.

Powered by the Perl programming language

what is programming?