New blog architecture

The design of this blog focuses on maintainability and ease of scraping. Access logs show frequent hits on robots.txt and index.xml, indicating significant traffic from scrapers and RSS readers.

The implementation avoids JavaScript, relying on semantic HTML to leverage browser reader modes. CSS is kept separate to allow for future changes. The workflow involves writing in Typst and using its HTML export feature. A language that handles data well was required for the build system, leading to the evaluation of OCaml and Haskell.

Implementation: OCaml and Haskell

OCaml

The OCaml implementation was integrated using gemini-cli. The initial Nix development shell setup built OCaml from scratch, which resulted in a long build time. The resulting code structure is similar to a script.

let purge_and_create_dist () =
(if Sys.file_exists dist_dir then
let cmd = Printf.sprintf "rm -rf %s" dist_dir in
let _ = Sys.command cmd in
());
Unix.mkdir dist_dir 0o755

let inject_footer content =
let footer = get_fragment "footer" in
let re_body_end = Str.regexp_case_fold "</body>" in
try
let pos = Str.search_forward re_body_end content 0 in
let before = String.sub content 0 pos in
let after = String.sub content pos (String.length content - pos) in
before ^ "\n" ^ footer ^ "\n" ^ after
with Not_found -> content ^ "\n" ^ footer
Haskell

The Haskell implementation was developed with Gemini. There was no prior experience with the language, but the code is straightforward. The build process proved faster than the OCaml version. Because the Haskell implementation is shorter, it is the chosen solution for now.

purgeAndCreateDist :: IO ()
purgeAndCreateDist = do
exists <- doesDirectoryExist distDir
when exists $ removeDirectoryRecursive distDir
createDirectoryIfMissing True distDir

injectFooter :: T.Text -> IO T.Text
injectFooter content = do
footer <- getFragment "footer"
let bodyEnd = "</body>"
let (before, after) = T.breakOnEnd bodyEnd content
if T.null before
then return $ content <> "\n" <> footer
else return $ T.dropEnd (T.length bodyEnd) before <> "\n" <> footer <> "\n" <> bodyEnd <> after

Original Outline:

Generation Prompt: “i have added a skeleton post new-blog.typ. turn it into a blog article. make sure not to keep repeating the same phrases. Stick to the main points. Do not assume any feelings I might have had. Only use the info provided. At the bottom of the post include a line and underneath include the original outline and the prompt used to generate the article. Mark them as such so a reader would know”