[web-devel] Re: yesod stylesheet serving

Michael Snoyman michael at snoyman.com
Mon Jul 5 15:04:37 EDT 2010


On Mon, Jul 5, 2010 at 10:01 PM, Michael Snoyman <michael at snoyman.com>wrote:

> 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 <simon at joyful.com> 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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/web-devel/attachments/20100705/a44ab384/attachment.html


More information about the web-devel mailing list