Reputation: 61121
When I build my snap project, it does not include any of my static resources or templates.
My project structure is as follows:
site.cabal
\src
\snaplets
\heist
*.tpl
\static
\css
*.css
\images
*.jpg
Currently, I am deploying my binary to the server separately from my static files (which I simply copy over).
Is there a better way to do this? Any help appreciated.
Upvotes: 4
Views: 378
Reputation: 174
You can embed static files into your code using Data.FileEmbed
found in file-embed. I create a res
directory and drop everything static in there. Then use the following code to access it.
{-# LANGUAGE TemplateHaskell #-}
-- src/Resources.hs
module Resources ( getResource, listResources ) where
import qualified Data.ByteString as BS
import Data.FileEmbed
resources :: [(FilePath, BS.ByteString)]
resources = $(embedDir "res")
getResource :: FilePath -> Maybe BS.ByteString
getResource path = findResource resources
where
findResource [] = Nothing
findResource ((p,cont):xs) = if p == path
then (Just cont)
else findResource xs
listResources :: [FilePath]
listResources = map fst resources
Then in the code where you define your routes, you create a list of (route, handlers)
:
-- src/Site.hs
resRoutes :: [(ByteString, Handler App App ())]
resRoutes = map f listResources
where
f res =
(TE.encodeUtf8 $ T.pack res, (writeBS . fromJust) $ getResource res)
-- in your SnapletInit
app = makeSnaplet "app" "" Nothing $ do
addRoutes resRoutes
addRoutes otherRoutes
return $ App ()
File res/css/custom.css
in your file system is accessible via http://<site>/css/custom.css
. This works with text files, and binary files like images.
You should note that the static files are "consumed" during compilation of src/Resources.hs
so if you add, modify or delete resources you'll have to trigger a rebuild of that file.
I'm still looking for a way to build the Heist templates into the executable. Should be similar, only modifying how Heist looks up and reads the files, need to use the resource list instead.
Upvotes: 0
Reputation: 7282
For my most recent project I created a script called deploy.sh that looks something like this:
#!/bin/sh
rf -fr ../myapp-deploy/*
cp -R dist/build/myapp/myapp log snaplets static ../myapp-deploy
Then I deploy everything in myapp-deploy. This can be done a number of ways. One approach is to zip it up and ftp/scp it to your deployment server. Another approach that I like and have used in the past is to make myapp-deploy into its own git repository. Then after I run deploy.sh, I commit everything in myapp-deploy and push it to some centralized repository. Then on my deployment server I can do git pull && killall -HUP myapp
to go live with the most recent version. The benefit to having it in a git repository is that I can always revert back to the previous version very easily. If you have dynamic filesystem resources created by your users, then this approach might not work as well for you.
At the end of the day, reliable production deployment is a complex problem that needs an individualized approach. Something like this can be a useful guide, but can't replace the need for good IT engineering.
Upvotes: 2
Reputation: 26167
You can't embed your static files into the executable while still having things work as they should wrt the rest of snap.
Also, in Windows there's a "resource system" in PE files which lets you embed resources, but on Linux/Unix there isn't. So, using external files is the only reliable way to ensure that they are reachable on every platform.
Additionally, you might want to add or remove static files when users e.g. upload them, and that's not possible with embedded resources.
Upvotes: 2