linguiniの✨ブログ✨

ブログ生成にHintつかいはじめました&Hakyll.loadAllSnapShotsで嵌まった

仮のTL;DR

Lucidからhtmlを生成するときにHint(Runtime Haskell interpreter)使うようにして新しい記事を作るたびにHakyllをビルドしなくてよくなった。Hakyll.loadAllSnapShotsは型がわからないと動かないので使ってるところを書く前はエラーが出るが型注釈を書けばエラーは消える

{-# LANGUAGE OverloadedStrings #-}

module Main where

import Control.Arrow
import Control.Exception (Exception (displayException))
import qualified Data.ByteString.Lazy.Char8 as BS
import Data.Functor.Identity
import Data.String (IsString)
import qualified Data.Text.Lazy as Text
import Hakyll
import Language.Haskell.Interpreter (OptionVal ((:=)))
import qualified Language.Haskell.Interpreter as Hint
import Lucid
import System.IO (hPutStrLn, stderr)
import System.Process (readProcess)
import Template (BlogPost (..), IndexData (..), Link, https)

postsDir = "posts/*/"

postsHaskell = fromGlob $ postsDir <> "*.hs"

postsHtml = fromGlob $ postsDir <> "*.html"
 
 redirectsDir :: IsString s => s
 redirectsDir = "redirects"
 
 defaultIndexData :: IndexData
 defaultIndexData =IndexData
│ │ { externals =
│ │ │   fmap
│ │ │   │ (first https)
│ │ │   │ [ ("twitter.com/1inguini", "Twitter"),
│ │ │   │ │ ("twitter.com/1inguini1tasita", "Twitterの飲精アカウント"),
│ │ │   │ │ ("github.com/1inguini", "GitHub"),
│ │ │   │ │ ("linguini.booth.pm", "BOOTH"),
│ │ │   │ │ ("www.amazon.co.jp/hz/wishlist/dl/invite/ieqolZ4?ref_=wl_share", "干し芋"),
│ │ │   │ │ ("vrchat.com/home/user/usr_7be90808-2858-4707-b1b9-b2b5636ba686", "VRChat")
│ │ │   │ ],
│ │ │ articles = []
│ │ }

main :: IO ()
main =
│ hakyllWith defaultConfiguration {destinationDirectory = "docs"} $
│ │ let pathAndFeedConfirguration = "Path&FeedConfiguration"
│ │ │in do
│ │ │    create ["index.html"] $ do
│ │ │    │ route idRoute
│ │ │    │ compile $ do
│ │ │    │ │ maybeIndex <- unsafeCompiler $ interpret "pages/Index.hs" "index" (Hint.as :: IndexData -> Html ())
│ │ │    │ │ case maybeIndex of
│ │ │    │ │ │ Left e -> do
│ │ │    │ │ │ │ unsafeCompiler $ hPutStrLn stderr $ displayException e
│ │ │    │ │ │ │ fail "interpret"
│ │ │    │ │ │ Right index -> do
│ │ │    │ │ │ │ articles <-
│ │ │    │ │ │ │ │ fmap (itemBody >>> second feedTitle)
│ │ │    │ │ │ │ │ │ <$> ( loadAllSnapshots postsHaskell pathAndFeedConfirguration ::
│ │ │    │ │ │ │ │ │ │       Compiler [Item (FilePath, FeedConfiguration)]
│ │ │    │ │ │ │ │ │ │   )
│ │ │    │ │ │ │ makeHtml $
│ │ │    │ │ │ │ │ index defaultIndexData {articles = articles}

│ │ │    match postsHaskell $ do
│ │ │    │ route $ setExtension "html"
│ │ │    │ compile $ do
│ │ │    │ │ src <- getResourceFilePath
│ │ │    │ │ (Just path) <- getRoute =<< getUnderlying
│ │ │    │ │ result <- unsafeCompiler $ interpret src "post" (Hint.as :: BlogPost Identity)
│ │ │    │ │ case result of
│ │ │    │ │ │ Left e -> do
│ │ │    │ │ │ │ unsafeCompiler $ hPutStrLn stderr $ displayException e
│ │ │    │ │ │ │ fail "interpret"
│ │ │    │ │ │ Right blogpost -> do
│ │ │    │ │ │ │ makeItem (path, feedConfig blogpost)
│ │ │    │ │ │ │ │ >>= saveSnapshot pathAndFeedConfirguration
│ │ │    │ │ │ │ makeHtml $ html blogpost

│ │ │    match postsHtml $ do
│ │ │    │ route idRoute
│ │ │    │ compile getResourceBody
            

makeHtml :: Html () -> Compiler (Item String)
makeHtml html =
│ unsafeCompiler
│ │ ( readProcess
│ │ │   "npx"
│ │ │   ["js-beautify", "--type=html", "-"]
│ │ │   (Text.unpack $ renderText html)
│ │ )
│ │ >>= makeItem

interpret filepath expr as =
│ Hint.runInterpreter $ do
│ │ Hint.loadModules [filepath]
│ │ Hint.setTopLevelModules ["Main"]
│ │ Hint.setImports ["Prelude", "Lucid", "Template"]
│ │ Hint.setImportsQ [("Data.ByteString.Lazy", Just "BS")]
│ │ Hint.interpret expr as

コメント欄