今天,我想把之前贝叶斯演示里的CSS和JS文件编译进程序,部署的时候就只用一个二进制程序就可以了。
最后希望这样可以使用:
result_css :: Text
result_css = $(loadFile "static/css/result.css")
我的第一次尝试:
import qualified Data.Text.IO as TIO
loadFile :: FilePath -> Q Exp
loadFile filepath = do
file <- runIO $ TIO.readFile filepath
[| file |]
因为只有Lift
类的值才能直接插进 [| ... |]
, 但是Text
不是Lift
类,我试着自己实现,无果。
然后我去看shakespeare
的代码,更复杂了。最后我发现了file-embed
,它不是直接插入ByteString
, 而是返回了一个AppE
表达式(类型是Exp
), 在这个表达式里转换。
我简化一点,足够自己用:
loadFile :: FilePath -> Q Exp
loadFile filepath = do
str <- runIO $ readFile filepath
convert <- [| T.pack |]
return $ AppE convert $ LitE $ StringL str
在Scotty里,我用一个HashMap来放文件:
cssFiles :: H.HashMap Text Text
cssFiles = H.fromList
[ ("login.css", $(loadFile "static/css/login.css"))
, ("result.css", $(loadFile "static/css/result.css"))
]
然后在Handler里lookup:
get "/static/css/:file" $ do
file <- param "file"
case H.lookup file cssFiles of
Nothing -> status status404
Just f -> text f >> header "Content-type" "text/css"
这比原来用wai-middleware-static
麻烦多了。