Deployed
Cooking Recipes
A collection of recipes without the intrusive ads. Minimally designed to make grocery shopping and cooking easier.
Recipe websites embody some of the worst aspects of the modern web. This app is a custom static site generator, written in Haskell, that converts structured Markdown recipe files into mobile-friendly HTML pages without ads or a hostile user experience. It has bare minimum JavaScript logic for making grocery shopping and cooking easier.
Tech Stack
- Haskell (GHC, Cabal, Hspec)
- HTML/CSS/JS
- NGINX
Architecture
- Produces a static website hosted behind an NGINX reverse proxy.
- Recipes are structured Markdown files with fixed sections (Ingredients, Directions, Notes, etc.).
- Inside the generator:
- A custom parser reads each Markdown file and converts it into a type-safe
Recipedata type via a builder DSL using Haskell’s&operator. - HTML templates with
{{PLACEHOLDER}}placeholders are used to generate pages in thedist/output directory. - Public assets (pictures of final dishes, mostly) are copied to the
dist/directory.
- A custom parser reads each Markdown file and converts it into a type-safe
- Hspec regression tests compare the latest build output to expected HTML pages.
Challenges
- Designing a Markdown structure that is strict enough to parse reliably but flexible enough for real recipes.
- E.g., optional sections, numbered steps with sublists.
- Balancing the desire for minimal CSS with the need for a highly accessible and useful UI.
- Regression tests require manual fixture updates whenever templates change, which adds friction to UI tweaks.
Learnings
- This was my first practical Haskell project, so I put many functional programming patterns into practice.
- Haskell’s type system makes data modeling expressive.
- The type-safe DSL and builder pattern are readable and checked at compile time.
- Simple line-by-line parsing is sufficient when input format is well-defined.
- Regression tests come at the cost of a manual update step (or at least manual review).
- A minimal template engine (plain string replacement) is entirely sufficient for a static site of this scope.
- AI agents are very reliable for extracting recipe info from images or URLs, and can reformat directions to be easier to follow during actual cooking.
- E.g., “Mix in 1/2 cup tomatoes” vs “Mix in the tomatoes,” which requires scrolling to the ingredient list for the quantity.
For the Future
- If recipe count grows, I’ll likely need some kind of tagging or search functionality.
- Adding new recipes involves manually composing prompts depending on the recipe source.
- I could likely build an agent workflow that is pointed towards the recipe source.
- The agent could then handle creating the Markdown file, standardizing language, running tests, and opening a PR.
- Explore rendering to PDF for a printable recipe format.