Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8399e00
commit c58a744
Showing
10 changed files
with
453 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
| title: Heist 0.10...now with a >3000x performance improvement | ||
| author: Doug Beardsley <mightybyte@gmail.com> | ||
| published: 2012-12-09T20:55:00+0100 | ||
| updated: 2012-12-09T20:55:00+0100 | ||
| summary: Release notes for Heist 0.10 | ||
|
||
The Snap team is excited to announce the release of Heist 0.10. For this | ||
massively backwards-incompatible release we went back to the drawing board and | ||
re-wrote Heist from the ground up with performance in mind. But was Heist | ||
actually slow? Nobody has actually complained about it, but yes, Heist was | ||
slow. Well...it was until now. | ||
|
||
![](/media/img/heist-perf.png) | ||
|
||
Note that this chart is log scale. The difference is so drastic that if the | ||
chart was linear scale, the bars for Heist 0.10 wouldn't even show up! The | ||
three pages benchmarked are taken directly from snapframework.com, so they are | ||
real-world examples. Heist 0.10 gives an improvement of more than 3000x for | ||
snaplets.tpl, 2000x for about.tpl, and 700x for faq.tpl. The improvement for | ||
faq.tpl is smaller because most its content is statically generated by pandoc, | ||
so Heist only has to traverse a small DOM compared to the other two templates. | ||
|
||
To understand what happened here, we need to go back to the beginning. When | ||
we originally wrote Heist, speed was not our goal. Instead we wanted to see | ||
how far a simple concept like binding Haskell code to HTML nodes could take us | ||
in solving the problem with HTML boilerplate. Now, two and a half years | ||
later, we've discovered that it's an incredibly powerful and enjoyable model | ||
for web programming. | ||
|
||
Heist achieves this by traversing the DOM, executing splices to generate | ||
replacement nodes, and recursively traversing those nodes until all splices | ||
have been executed. A significant part of Heist's power lies in the fact that | ||
this transformation happens at runtime every time a template is served, so the | ||
splice computations are running in your web server monad and have access to | ||
all the data from the HTTP request. Once this transformation is complete, the | ||
resulting DOM is rendered to a ByteString and served back in the HTTP | ||
response. This is really slow when compared with concatenative template | ||
systems like StringTemplate that just blast out interleaved static and dynamic | ||
chunks of data. Therefore it should be no surprise that splicing is slow, as | ||
it allows for much more expressiveness and power. | ||
|
||
However, we realized that a lot of the transformations could be done at load | ||
time and be preprocessed to an intermediate representation. This consists of | ||
static ByteStrings interleaved with deferred dynamic computations that still | ||
give you the power of being able to access the web server's runtime monad. | ||
This "compiled splice" as we call it works quite a bit differently from the | ||
old model of splices. It is also strictly less powerful, so we kept the | ||
ability to use the old "interpreted splice" model if you really need the power | ||
and can afford the performance penalty. | ||
|
||
While we were making backwards incompatible changes, we decided to clean up | ||
everything. This included reorganizing the modules and any other changes we | ||
felt would improve the overall quality and readability of the code base. It | ||
will be a bit of work to migrate existing code to Heist 0.10, but the old | ||
interpreted splices are still available and allow you do a gradual transition. | ||
We also added a new feature called attribute splices that allows you to | ||
abstract attributes in ways that weren't possible before. | ||
|
||
For more detailed information about the new features, check out the tutorials | ||
in the [heist section](/docs#heist) of our docs page. After you have read | ||
those and are ready to upgrade your site, you might want to follow our [migration | ||
guide](https://github.com/snapframework/heist/wiki/Migrating-Snap-Applications-to-Heist-0.10) | ||
to help you with the transition to 0.10. The migration guide is a github | ||
wiki, so feel free to help us make it clearer and more complete. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
58 changes: 58 additions & 0 deletions
58
snaplets/heist/templates/docs/tutorials/AttributeSplices.lhs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
Attribute Splices | ||
================= | ||
|
||
Attribute splices are new in Heist 0.10. They solve the problem of wanting to | ||
be able to dynamically make empty attributes appear or disappear with a splice | ||
without binding a splice to the whole tag. This issue comes up most | ||
frequently when dealing with empty attributes such as HTML's "disabled" or | ||
"checked". | ||
|
||
> module Heist.Tutorial.AttributeSplices where | ||
> import Heist.Tutorial.Imports | ||
|
||
Consider a page with several radio buttons. You want the correct one to be | ||
selected based on the value of a parameter in the HTTP request. The HTML | ||
would look something like this: | ||
|
||
<input type="radio" name="color" value="red" checked>Red</input> | ||
<input type="radio" name="color" value="green">Green</input> | ||
<input type="radio" name="color" value="blue">Blue</input> | ||
We want to automatically generate the "checked" attribute appropriately. This | ||
could be done with a splice bound to the input tag, but there might be a | ||
number of other input tags on the page, so your splice would at best be | ||
executed on more tags than necessary and at worst not have the granularity | ||
necessary to work properly. The ${} syntax for splices inside of attribute | ||
values also won't work because it can only affect an attribute's value. It | ||
can't make the attribute disappear entirely. This problem can be solved | ||
nicely with attribute splices that have the following type: | ||
< type AttrSplice m = Text -> m [(Text, Text)] | ||
An attribute splice is a computation in the runtime monad that takes the value | ||
of the attribute it is bound to as its argument and returns a list of | ||
attributes to substitute back into the tag. Here's how we might implement a | ||
splice to solve the above problem. | ||
> autocheckedSplice :: Text -> StateT Text IO [(Text, Text)] | ||
> autocheckedSplice v = do | ||
> val <- get -- app-specific retrieval of the appropriate value here | ||
> let checked = if v == val | ||
> then [("checked","")] | ||
> else [] | ||
> return $ ("value", v) : checked | ||
In this toy example we are using `StateT Text IO` as our "runtime" monad where | ||
the Text state holds the value of the radio button that should be checked. We | ||
assume that the current value we're checking against is passed as the bound | ||
attribute's value, so we compare that against the value to be checked. Then | ||
we return a list with the appropriate value and the checked attribute if | ||
necessary. We bind this splice to the "autocheck" attribute by adding it to | ||
the hcAttributeSplices list in HeistConfig. | ||
To make everything work we use the following markup for our radio buttons: | ||
<input type="radio" name="color" autocheck="red">Red</input> | ||
<input type="radio" name="color" autocheck="green">Green</input> | ||
<input type="radio" name="color" autocheck="blue">Blue</input> | ||
Oops, something went wrong.