To suggest new recipes, send an e-mail to hello@lchristmann.com!
- 1. Basics
- 2. Testing
- 3. Cloud Infrastructure
- 4. Deployment (CI/CD Pipeline)
- 5. Negative SEO
- 6. App Content
- 7. Development Roadmap
This project uses Vite, which requires Node.js version 18+ or 20+.
Run npm install to install project dependencies (which are specified in package.json).
Not relevant for working on this, just FYI. This project was created by
- executing
npm init vite recipe-app - following the TailwindCSS installation instructions and
- adding the
@import "tailwindcss";tosrc/style.css
- adding the
Run npm run dev.
RULE: Images must be named like the recipe title specified in
src/assets/recipes/*.json,
but lowercase and with whitespaces replaced by hyphens, e.g. Pommes Bowl -> pommes-bowl.webp
German Umlaute must be transcribed according to the following rules: ä -> 'ae', ö -> 'oe', ü -> 'ue', ß -> 'ss'.
When adding an image to public/images and you want to see that while developing (locally), run npm run generate:manifest.
For deployment, this is not needed, because in the build script, this command is already included.
For managing the images, I wrote three custom npm scripts:
npm run show:missing-imagesnpm run validate:images
Optimizations I have to taken already:
- using lazy loading on images of the recipes list, which are "below the fold" (not on screen for the user): only the first five images are eagerly loaded
- using an image format with best efficiency (compression and quality): WebP
- having caching (set to two weeks) for the whole app and distribution via CDN (AWS CloudFront) -> fast global delivery with few roadtrips to the source (S3 bucket is the source, see Cloud Infrastructure)
- include images in a small resolution and roughly 2/1 aspect ratio (but 3/1 in the recipe list should also look fine)
- somethig like 1200 x 600 is very good
Run npm run build. You can then view this build ("have it served") with npm run preview.
This project uses a lot of custom Node.js scripts which can be found in the /scripts folder of this project.
They can be executed via node scripts/<nameOfTheScript> or via the npm commands shown below (or see package.json).
aggregateRecipes.js:
- processes all single recipe JSON files
src/assets/recipes/[main,side,supper,dessert]/*.jsoninto aggregate JSON filessrc/assets/recipes/[main,side,supper,dessert].json - and adds the properties
hasImageand (if so)imageUrlalso to the single recipe JSON files
cleanRecipes.js: removes those added hasImage and (if so) imageUrl properties - a helper script to keep that unnecessary data away from version control
createRecipe.js: can be called like npm run create main/neues-rezept and creates an appropriate starting template JSON file
generateLabelsManifest:
- looks for all unique labels in the respective labels arrays of the aggregate JSON files and writes them to a
labelsManifest.jsonfor theSearchAndFilter.vuecomponent to know which labels exist and shall be displayed in the dropdown.
showMissingImages: shows all recipes that don't have an image yet
validateImages: validates that all files in the image category directories are WEBP files and can be associated with a recipe JSON file (the filename of both must be the same, it's just different extensions)
validateRecipes: checks that the recipe JSONs are in correct format (allowed properties and data types)
The Vitest Unit Tests in the tests/unit folder can be run with npm run test.
## 3. Cloud Infrastructure
The following diagram shows the Amazon Web Services cloud infrastructure the site is running on.
It's a classic static website hosting via S3 and CloudFront setup.
Note that the Origin-Access-Control is used to only enable CloudFront to access the S3 bucket.
For having the subdomain with an own SSL certificate
- one CNAME record had to be added to
lchristmann.comas verification of domain ownership towards AWS Certificate Manager - one A record with an alias to the CloudFront distribution
Deployment is automated with a GitHub Actions CI/CD pipeline which is triggered by every commit in the Git repository (see .github/workflows/cicd.yml).
Since this is purely a hobby project, there's no point in having it indexed by search engines.
Therefor they are discouraged from crawling and indexing it at all by
- the
robots.txtfile - the
<meta name="robots" content="noindex, nofollow">tag inindex.html
Recipe JSON files must be kebab case (lowercase and words separated by hyphens). They are allowed to contain German umlauts, like "käsekuchen".
Labels are generated by the npm run generate:labels-manifest command (that's only possible after the npm run aggregate:recipes command, because the labels generation uses the aggregate JSON files). To see the existing labels, you can run both commands and look at the src/assets/recipes/labelsManifest.json or just run npm run dev or npm run build, which will run both commands, too.
To create a new recipe, there's a helper script that you can use: npm run create main/rezept-name.
- have the whole recipes JSON data
src/assets/recipesin the cloud only and develop arecipe-app-managerapplication in another repository, with which I can manage the recipes from anywhere- I can create new recipe JSON files via the GitHub Mobile App already though, so it's not too bad already