Building notes, projects, and occasional rants

A new look at Mason

On my way to E5, I have to deal with all the legacy sites that came before it, and the vast majority of them are written in Mason.

At the time, we used HTML::Mason 1.05, and only after 1.30-ish (when the internal buffering changes introduced in the 1.10 release where reverted) did we upgraded to something more recent. To get an idea of the size of this Mason project, the current sites have a little over 450 different components across 7 sites (different layouts but same content) and 1 management site. A lot of those components are no longer in use, and where left there due to bad VCS practices. I would estimate about 200 actual useful components. And it makes heavy use of autohandlers, dhandlers, and multiple component roots, to implement site inheritance.

The E5 template discussion is also still on my mind, without a clear winner yet.

And finally, last week I read Jonathan Swartz article about what Mason 2.0 would look like.

So I took the time last night to re-evaluate Mason. As most powerful tools (and be sure that it is a very powerful tool), the problem with Mason is that you can easlly make a big mess of things. More than with other solutions like Catalyst and Mojo, that provide you with a clear separation of Controller, Model and View, Mason make is very easy to mix the three. You could end up with a lot of logic that should be in your models inside your templates.

But it has several advantages:

  • its easy to start and add a new page. Just create the file and start typing: no need to jump between controller and template, and a restart (this alone makes for speedy development);
  • it has decent wrapper functionality for skinning: autohandlers are great;
  • the multiple component roots logic is very powerful, and its used both during the dispatch phase and component calls;
  • the view logic is Perl: no need to learn a new language and be exasperated with their limitations like TT.

There are several downsides of course: for one, the split of Controller/View of modern frameworks allows you to reuse controller logic with multiple views. For example, you could output HTML, JSON and XML with the same controller code.

But the biggest downside is this: deployment is a bitch.

For production environments, deployment usually means mod_perl but I find FastCGI easier to deploy now-a-days. Yet, this option is only briefly mentioned on the MasonHQ site.

So I created a small experimental project (you can find all the files at the exp-mason-fcgi project on GitHub). It has a FastCGI startup script to power two virtual hosts. Each one shares a master component root, and has a local per-site component root to override the master site behavior when needed.

The setup works just fine under nginx+FastCGI (partial nginx.conf included), but I did get into some trouble. Mason usually delegates some stuff to Apache and without his big daddy around, he can get lost.

The first problem is directory index files. When you request a directory, Apache will help Mason out and point it to the proper index.html file. Without Apache, request to http://your-fastcgi-mason-site/ will just fail, because Mason cannot find the component for /. It has no logic to map / into /index.html for example.

You could implement this with a global dhandler, and it is probably the best solution, because it can also deal with 404 situations (another one that Apache could cleanup after).

I have a proof of concept hack in the repo that mimics the Apache DirectoryIndex directive. It is a hack, it should be in the and not in the Request. I'll clean it up later. But it does work, and it might be useful in some scenarios.

This patch makes a / request work just fine.

The second problem I have with Mason is the order of evaluation of templates. The current order for a request to /index.html is /autohandler which calls $m->call_next and that calls the /index.html component.

This makes it hard to influence the wrapper with content generated by the /index.html component.

The solution was to create a new HTML::Mason::Request method called scall_next(). It merges the $m->call_next() and the $m->scomp() calls into one, and allows me to use it in a autohandler like this. The $m->scall_next() will call the next component, get the generated HTML, and only then generate the HTML wrapper.

The last piece of the puzzle is a way for the /index.html and the parent autohandler to communicate, for example, to pass along the title for the page.

The Mason-recommended way is to use $m->notes() API, similar to the Catalyst stash concept. It works very well, but I prefer to take advantage of the fact that all components live inside the HTML::Mason::Commands namespace and just declare a shared %stash there and clean it up per request. With this, its easy to implement dynamic page titles.

All in all, I keep coming back to Mason. I do like most of what it provides, and for quick sites, it beats all the other alternatives in Perl-land.

A couple of months ago there was some discussion about a option to give web developers that was FTP friendly, in that you could upload your pages to a server and it would just work. Mason is the closest that Perl has to that goal.

But the deployment must be made simpler, and that I one of the things that Mason 2.0 should focus on: make it simpler to deploy.

So my laundry list for Mason 2.0 (and most of them can be implemented on 1.x):

  • FastCGI support out-of-the-box;
  • support for directory index files (without using dhandlers);
  • $m->scall_next;
  • better hooks for debugging and 404 errors.

I don't know. I'm strongly considering go Mason all the way for E5, and if that goes forward, I guess I'll have to write these four pieces myself.