Re: yesod stylesheet serving

On Mon, Jul 5, 2010 at 10:01 PM, Michael Snoyman
Hey Simon,
Firstly, I'm not sure if your message went through to the rest of the list, but at least they should see this reply.
On Mon, Jul 5, 2010 at 8:02 PM, Simon Michael
wrote: Hi Michael.. thanks again for the great real-world-driven updates to Yesod et al. I'm looking forward to trying widgets. Meanwhile...
I'm having trouble serving a stylesheet that Chrome will recognise, because this:
getStyleCss :: Handler HledgerWebApp RepPlain getStyleCss = do app <- getYesod let dir = appWebdir app s <- liftIO $ readFile $ dir > "style.css" header "Content-Type" "text/css" return $ RepPlain $ toContent s
serves up this:
$ curl -i http://localhost:5000/style.css HTTP/1.1 200 OK Content-Type: text/plain; charset=utf-8 Set-Cookie: _SESSION=...; path=/; expires=2010-07-05T18:41:35-00:00 Content-Type: text/css
Note the two content-types. (Also, no content-length header; I don't know if that matters.)
Let me explain. In general, you don't need to explicitly set content-type headers in Yesod. Yesod determines the content type automatically based on the return type of the handler function. In particular, a handler must return an instance of HasReps, which allows a handler to specify multiple representations of data if it so desires.
By using a return type of RepPlain, you're telling Yesod to set a content-type header of "text/plain". Instead, you probably want to use a different return type. For example, you could use the [(ContentType, Content)] return type.
However, in your case, you have two much better options (in my opinion):
* Use the Static helper. * Use the sendFile function. When using sendFile, you short-circuit the remainder of the handler code and immediately send a file. You get to explicitly state the content type, and also get another bonus: some backends optimize the sending of static files. For example, the SimpleServer backend using a sendfile system call, so you avoid unnecessary data copying.
Your examples seem to serve css using Yesod.Helpers.Static. I'm not using
that because it seems to require a file path known at compile time, or am I wrong ? I get the path at run-time with cabal's getDataFilename.
No, the path does not need to be known at compile time, but you'll need to supply it when constructing the Static data type value. All of this would happen when initializing your site argument; I can put together an example of this if you like.
And an unrelated question: what's the meaning of the type returned by a
hamlet template ? I see one of your examples returning something like Hamlet AppRoutes, but my app will accept only Hamlet String for some reason. I wouldn't worry except hamletToRepHtml seems to require the former.
type Hamlet url = (url -> String) -> Html ()
The Html is a datatype taken from Blaze, which is what let's Hamlet get all of the performance advantages of that library. The url has to do with the type-safe URL feature: every site has a URL datatype associated with it, which defines all valid routes into an application. Of course, we can't just display Haskell datatypes in our HTML code, so Hamlet takes a "url rendering function" as its first argument.
In general, you shouldn't need to be bothered with any of these details, as Yesod automates all of the rendering details for you. If you point me to the code in question, I'll take a look.
Michael
participants (1)
-
Michael Snoyman