I’ve just pushed version 0.4-beta1 of sacy
to its github repository. Aside of requiring
PHP 5.3 now, it also has support for transforming contents of inline-tags.
So if you always wanted to write
type="text/coffeescript">
hello = (a)->
alert "Hello #{a}"
hello "World"
and have the transformation done on the server-side, then I have good news
for you: Now you can! Just wrap the script with
{asset_compile}...{/asset_compile}
.
I’m not saying that having inline-scripts (or even stylesheets) is a good idea
but sometimes, we have to pass data between our HTML templates and the JS
code and now we can do it in Coffee Script.
Development note
When you take a look at the commits leading to the release, you will notice
that I more or less hacked the support for inline tags into the existing
codebase (changing the terminology from files to work units in the process
though).
Believe me, I didn’t like this.
When I sat down to implement this, what I had in mind was a very nice
architecture where various components just register themselves and then
everything falls into place more or less automatically.
Unfortunately, what ever I did (I used git checkout .
about three times) to
start over, I never got a satisfactory solution:
-
sometimes, I was producing a ton of objects, dynamically looking up what
methods to call and what classes to instantiate.This would of course be very clean and cool, but also terribly slow. Sacy
is an embeddable component, not an application in its own right. -
sometimes, I had a simplified object model that kind of worked right until I
thought of some edge-case at which point we would have either ended up back in
hack-land or the edge-cases would have had to remain unfixed -
sometimes I had something flexible enough to do what I need, but it still
had code in it that had to know whether it was dealing with instances of Class
A or Class B which is as inacceptable as the current array-mess.
In the end, it hit me: Sacy is already incomplete in that it simplifies the
problem domain quite a lot already. To cleanly get out of this, I would have to
actually parse and manipulate the DOM instead of dealing with regexes and I
would probably even have to go as far as to write a FactoryFactory
in order
to correctly abstract away the issues.
Think of it: We have a really interesting problem domain here:
- the same type of asset can use different tags (style and link for
stylesheets) - Different attributes are used to refer to external resources (href for
stylesheets, src for scripts) - File-backed assets can (and should) be combined
- Conent-backed assets should be transformed and immediately inlined
- Depending on the backing (content or file), the assets use a different
method to determine cache-freshness (modification-time/size vs. content) - And last but not least, file based asset caching is done on the client side,
content based asset caching is done on the server-side.
Building a nice architecture that would work without the if
s I learned to
hate lately would mean huge levels of indirections and abstractions.
No matter what I tried, I always ended up with a severe case of object-itis and
architectur-itis, both of which I deemed completely inacceptable for a
supposedly small and embeddable library.
Which is why I decided to throw away all my attempts and make one big
compromise and rely on CacheRenderer::renderWorkUnits
to be called with
unified workunits (either all file or all content-based).
That made the backend code a lot easier.
And I could keep the lean array
structure for describing a unit of work to do
for the backend.
I would still, at some point, love to have a nice way for handlers to register
themselves, but that’s something I’ll handle another day. For now, I’m happy
that I could accomplish my goal in a very lean fashion at the cost of a public
interface of the backend that is really, really inconvenient to use which leaves way too much code in the fronend.
At least I got away without an AssetFactoryFactory
though :-)