From db57fdc4b9222fe8204b155a0ca7e17d09c82985 Mon Sep 17 00:00:00 2001 From: Leyla Becker Date: Tue, 10 Feb 2026 17:29:30 -0600 Subject: [PATCH 01/10] feat: added item to post I want to make list --- posts/posts-I-want-to-make.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/posts/posts-I-want-to-make.md b/posts/posts-I-want-to-make.md index 9cce50f..9862c4b 100644 --- a/posts/posts-I-want-to-make.md +++ b/posts/posts-I-want-to-make.md @@ -101,4 +101,4 @@ description: "A blog post describing posts that I would like to make. Serves par - We shouldn't have speed limits, we score vehicles based on how they can strike a pedestrian or biker, and then limit the newtons that a vehicle can have based on the reaction time another person would have to react to their speed - National payment service like europe - digital right like the GDPR and ban DRM - \ No newline at end of file + - government provided 0 interest rate loans for emergency expenses \ No newline at end of file From af43876fcb13bfd812ca30053910ed616d940a31 Mon Sep 17 00:00:00 2001 From: Leyla Becker Date: Tue, 10 Feb 2026 17:50:26 -0600 Subject: [PATCH 02/10] feat: added more notes to posts I want to make --- posts/posts-I-want-to-make.md | 65 ++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/posts/posts-I-want-to-make.md b/posts/posts-I-want-to-make.md index 9862c4b..3ba46a8 100644 --- a/posts/posts-I-want-to-make.md +++ b/posts/posts-I-want-to-make.md @@ -5,6 +5,7 @@ description: "A blog post describing posts that I would like to make. Serves par ## project ideas - Tail scale, style, layer 3, personal connection, network and identity service. (reticulum might be this?) - package deployment for the reticulum style thing and distributed hosting via hashes of thr project and having overlays +- What I want to make quark into - Signal can't ensure the other person deletes messages and it should stop pretending it does. - IMS system for co-ops. - Meal Prep and Planning Service. @@ -32,7 +33,23 @@ description: "A blog post describing posts that I would like to make. Serves par - stop making objects with dynamic keys ## slice of life - I have a love hate relationship with Typescript -- Leyla's texting and communication preferences. + - I like the lambda functions + - I love union types + - I hate the ecosystem + - Why are things mutable + - Algebraic effects please + - So much legacy BS +- Leyla's texting and communication preferences + - nice websites + - https://dontasktoask.com/ + - https://xyproblem.info/ + - https://nohello.net/en/ + - https://modalzmodalzmodalz.com/#content + - What are you trying to say with a message + - Please avoid emoji + - I hate reactions + - Have an idea of what you want me to do with information in mind + - In person is better then over text - OSM is cool and you should use it - how to get started - overpass queries for community @@ -61,6 +78,52 @@ description: "A blog post describing posts that I would like to make. Serves par - Fettuccine Alfredo - White people Sushi - Enchiladas +- Recipes + - Bread machine bread + - Brownies + - Chicken broth powder + - Dal + - English Muffins + - White girl Yang Zhou Fried Rice + - White girl MaPo Tofu + - Jam + - Apple + - Strawberry + - Raspberry rhubarb + - Pear + - Stock + - Stuffing + - Soffritto + - Granola + - Pancakes + - Pizza Dough + - Pizza Sauce + - Souffle + - Sweet Corn + - Tapioca Pudding + - Tater Tot Hotdish + - Tikka Massala + - Tofu Scramble + - Smash Burgers + - Waffels + - Pancakes + - Tortellini + - Angle food cake + - banana Bread + - Cha + - Chilli + - Chorizo + - Creamy Mash Potatoes + - Madeleines + - Mochi + - Milk Shake + - Mozzarella + - Seitan + - Snickerdoodles + - Soft boiled egg + - Spice Cake + - Sushi Rice + - Apple Upside down cake - Drink preparation - Kombucha making - Cider making From f0a030c44a856d8fc44a2454d3ecc829754551de Mon Sep 17 00:00:00 2001 From: Leyla Becker Date: Wed, 11 Feb 2026 15:16:35 -0600 Subject: [PATCH 03/10] feat: added deployment flow --- flake.nix | 34 ++++++++++++++++++++++-- nix/configuration.nix | 44 +++++++++++++++++++++++++++++++ nix/hardware-configuration.nix | 30 ++++++++++++++++++++++ nix/module.nix | 33 ++++++++++++++++++++++++ nix/package.nix | 47 ++++++++++++++++++++++++++++++++++ 5 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 nix/configuration.nix create mode 100644 nix/hardware-configuration.nix create mode 100644 nix/module.nix create mode 100644 nix/package.nix diff --git a/flake.nix b/flake.nix index 91bbb0e..47d9e3b 100644 --- a/flake.nix +++ b/flake.nix @@ -1,5 +1,5 @@ { - description = "A Nix-flake-based Node.js development environment"; + description = "Volpe Blog"; inputs.nixpkgs.url = "https://flakehub.com/f/NixOS/nixpkgs/0.1.*.tar.gz"; @@ -19,9 +19,39 @@ pkgs = import nixpkgs {inherit overlays system;}; }); in { + packages = forEachSupportedSystem ({pkgs}: { + default = pkgs.callPackage ./nix/package.nix {}; + volpe = pkgs.callPackage ./nix/package.nix {}; + }); + devShells = forEachSupportedSystem ({pkgs}: { default = pkgs.mkShell { - packages = with pkgs; [node2nix nodejs pnpm sqlite]; + packages = with pkgs; [ + nodejs + nodePackages.pnpm + ]; + }; + }); + + nixosConfigurations.volpe = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + {nixpkgs.overlays = overlays;} + ./nix/configuration.nix + ]; + }; + + # Deployment helper - use with: nix run .#deploy + apps = forEachSupportedSystem ({pkgs}: { + deploy = { + type = "app"; + program = toString (pkgs.writeShellScript "deploy-volpe" '' + set -e + echo "Building and deploying to cyberian@69.61.19.180..." + nixos-rebuild switch --flake .#volpe \ + --target-host cyberian@69.61.19.180 \ + --sudo + ''); }; }); }; diff --git a/nix/configuration.nix b/nix/configuration.nix new file mode 100644 index 0000000..49131ac --- /dev/null +++ b/nix/configuration.nix @@ -0,0 +1,44 @@ +{ + config, + pkgs, + ... +}: { + imports = [ + ./hardware-configuration.nix + ./module.nix + ]; + + nix.settings.experimental-features = ["nix-command" "flakes"]; + nix.settings.trusted-users = ["root" "cyberian"]; + + swapDevices = [ + { + device = "/swapfile"; + size = 2 * 1024; # 2GB + } + ]; + + boot.loader.grub.enable = true; + boot.loader.grub.device = "/dev/vda"; + system.stateVersion = "24.11"; + + users.users.cyberian = { + isNormalUser = true; + extraGroups = ["wheel"]; + }; + security.sudo.wheelNeedsPassword = false; + + services.qemuGuest.enable = true; + services.acpid.enable = true; + + services.openssh = { + enable = true; + settings.PasswordAuthentication = false; + }; + + # Enable the volpe service + services.volpe = { + enable = true; + domain = "69.61.19.180"; + }; +} \ No newline at end of file diff --git a/nix/hardware-configuration.nix b/nix/hardware-configuration.nix new file mode 100644 index 0000000..b8efdbf --- /dev/null +++ b/nix/hardware-configuration.nix @@ -0,0 +1,30 @@ +# Do not modify this file! It was generated by 'nixos-generate-config' +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ + config, + lib, + pkgs, + modulesPath, + ... +}: { + imports = [ + (modulesPath + "/profiles/qemu-guest.nix") + ]; + + boot.initrd.availableKernelModules = ["ata_piix" "virtio_pci" "floppy" "sr_mod" "virtio_blk"]; + boot.initrd.kernelModules = []; + boot.kernelModules = ["kvm-amd"]; + boot.extraModulePackages = []; + + fileSystems."/" = { + device = "/dev/disk/by-uuid/1195bb4c-ddcb-4ad6-8109-d28170f169b1"; + fsType = "ext4"; + }; + + swapDevices = []; + + networking.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; +} diff --git a/nix/module.nix b/nix/module.nix new file mode 100644 index 0000000..06fe4d9 --- /dev/null +++ b/nix/module.nix @@ -0,0 +1,33 @@ +{ + config, + lib, + pkgs, + ... +}: let + cfg = config.services.volpe; + pkg = pkgs.callPackage ./package.nix {}; +in { + options.services.volpe = { + enable = lib.mkEnableOption "volpe blog"; + + domain = lib.mkOption { + type = lib.types.str; + default = "localhost"; + description = "Domain name for nginx virtual host."; + }; + }; + + config = lib.mkIf cfg.enable { + services.nginx = { + enable = true; + virtualHosts.${cfg.domain} = { + root = "${pkg}"; + locations."/" = { + tryFiles = "$uri $uri/ /index.html"; + }; + }; + }; + + networking.firewall.allowedTCPPorts = [80 443]; + }; +} \ No newline at end of file diff --git a/nix/package.nix b/nix/package.nix new file mode 100644 index 0000000..ace602e --- /dev/null +++ b/nix/package.nix @@ -0,0 +1,47 @@ +{ + lib, + stdenv, + nodejs_latest, + pnpm_10, + fetchPnpmDeps, + pnpmConfigHook, +}: let + nodejs = nodejs_latest; + pnpm = pnpm_10; +in + stdenv.mkDerivation (finalAttrs: { + pname = "volpe"; + version = "1.0.0"; + + src = lib.cleanSource ./..; + + nativeBuildInputs = [ + nodejs + pnpm + pnpmConfigHook + ]; + + # fetchPnpmDeps creates the offline store + pnpmDeps = fetchPnpmDeps { + inherit (finalAttrs) pname version src; + hash = "sha256-AiyDVGSxlfdqzuei0N0F3UOXlQVztxqyU7gBkZbUqOI="; + fetcherVersion = 3; # pnpm store version + }; + + buildPhase = '' + runHook preBuild + + pnpm build + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + mkdir -p $out + cp -r _site/* $out/ + + runHook postInstall + ''; + }) \ No newline at end of file From d90622efcce3e29108e413cafb0f387b3384d9f5 Mon Sep 17 00:00:00 2001 From: Leyla Becker Date: Wed, 11 Feb 2026 15:24:48 -0600 Subject: [PATCH 04/10] feat: added https to website --- nix/configuration.nix | 8 +++++--- nix/module.nix | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/nix/configuration.nix b/nix/configuration.nix index 49131ac..bdc5787 100644 --- a/nix/configuration.nix +++ b/nix/configuration.nix @@ -36,9 +36,11 @@ settings.PasswordAuthentication = false; }; - # Enable the volpe service services.volpe = { enable = true; - domain = "69.61.19.180"; + domain = "blog.jan-leila.com"; + extraDomains = ["volpe.jan-leila.com"]; + enableACME = true; + acmeEmail = "leyla@jan-leila.com"; }; -} \ No newline at end of file +} diff --git a/nix/module.nix b/nix/module.nix index 06fe4d9..c71a02b 100644 --- a/nix/module.nix +++ b/nix/module.nix @@ -13,21 +13,52 @@ in { domain = lib.mkOption { type = lib.types.str; default = "localhost"; - description = "Domain name for nginx virtual host."; + description = "Primary domain name for nginx virtual host."; + }; + + extraDomains = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = []; + description = "Additional domain names (aliases) for the virtual host."; + }; + + enableACME = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether to enable ACME (Let's Encrypt) for SSL certificates."; + }; + + acmeEmail = lib.mkOption { + type = lib.types.str; + default = ""; + description = "Email address for ACME certificate registration."; }; }; config = lib.mkIf cfg.enable { services.nginx = { enable = true; + recommendedTlsSettings = cfg.enableACME; + recommendedOptimisation = true; + recommendedGzipSettings = true; + recommendedProxySettings = true; + virtualHosts.${cfg.domain} = { root = "${pkg}"; + serverAliases = cfg.extraDomains; + forceSSL = cfg.enableACME; + enableACME = cfg.enableACME; locations."/" = { tryFiles = "$uri $uri/ /index.html"; }; }; }; + security.acme = lib.mkIf cfg.enableACME { + acceptTerms = true; + defaults.email = cfg.acmeEmail; + }; + networking.firewall.allowedTCPPorts = [80 443]; }; } \ No newline at end of file From 7682677cf6cfa6287b838da4ef002246ccc68b0d Mon Sep 17 00:00:00 2001 From: Leyla Becker Date: Wed, 11 Feb 2026 15:34:18 -0600 Subject: [PATCH 05/10] feat: added robots txt --- eleventy.config.js | 1 + robots.txt | 134 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 robots.txt diff --git a/eleventy.config.js b/eleventy.config.js index 1551fcb..b8668db 100644 --- a/eleventy.config.js +++ b/eleventy.config.js @@ -221,6 +221,7 @@ module.exports = (eleventyConfig) => { }); eleventyConfig.addPassthroughCopy("css"); + eleventyConfig.addPassthroughCopy("robots.txt"); return { dir: { diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000..be09253 --- /dev/null +++ b/robots.txt @@ -0,0 +1,134 @@ +User-agent: * +Allow: / + +User-agent: AddSearchBot +User-agent: AI2Bot +User-agent: AI2Bot-DeepResearchEval +User-agent: Ai2Bot-Dolma +User-agent: aiHitBot +User-agent: amazon-kendra +User-agent: Amazonbot +User-agent: AmazonBuyForMe +User-agent: Andibot +User-agent: Anomura +User-agent: anthropic-ai +User-agent: Applebot +User-agent: Applebot-Extended +User-agent: atlassian-bot +User-agent: Awario +User-agent: bedrockbot +User-agent: bigsur.ai +User-agent: Bravebot +User-agent: Brightbot 1.0 +User-agent: BuddyBot +User-agent: Bytespider +User-agent: CCBot +User-agent: Channel3Bot +User-agent: ChatGLM-Spider +User-agent: ChatGPT Agent +User-agent: ChatGPT-User +User-agent: Claude-SearchBot +User-agent: Claude-User +User-agent: Claude-Web +User-agent: ClaudeBot +User-agent: Cloudflare-AutoRAG +User-agent: CloudVertexBot +User-agent: cohere-ai +User-agent: cohere-training-data-crawler +User-agent: Cotoyogi +User-agent: Crawl4AI +User-agent: Crawlspace +User-agent: Datenbank Crawler +User-agent: DeepSeekBot +User-agent: Devin +User-agent: Diffbot +User-agent: DuckAssistBot +User-agent: Echobot Bot +User-agent: EchoboxBot +User-agent: FacebookBot +User-agent: facebookexternalhit +User-agent: Factset_spyderbot +User-agent: FirecrawlAgent +User-agent: FriendlyCrawler +User-agent: Gemini-Deep-Research +User-agent: Google-CloudVertexBot +User-agent: Google-Extended +User-agent: Google-Firebase +User-agent: Google-NotebookLM +User-agent: GoogleAgent-Mariner +User-agent: GoogleOther +User-agent: GoogleOther-Image +User-agent: GoogleOther-Video +User-agent: GPTBot +User-agent: iAskBot +User-agent: iaskspider +User-agent: iaskspider/2.0 +User-agent: IbouBot +User-agent: ICC-Crawler +User-agent: ImagesiftBot +User-agent: imageSpider +User-agent: img2dataset +User-agent: ISSCyberRiskCrawler +User-agent: Kangaroo Bot +User-agent: KlaviyoAIBot +User-agent: KunatoCrawler +User-agent: laion-huggingface-processor +User-agent: LAIONDownloader +User-agent: LCC +User-agent: LinerBot +User-agent: Linguee Bot +User-agent: LinkupBot +User-agent: Manus-User +User-agent: meta-externalagent +User-agent: Meta-ExternalAgent +User-agent: meta-externalfetcher +User-agent: Meta-ExternalFetcher +User-agent: meta-webindexer +User-agent: MistralAI-User +User-agent: MistralAI-User/1.0 +User-agent: MyCentralAIScraperBot +User-agent: netEstate Imprint Crawler +User-agent: NotebookLM +User-agent: NovaAct +User-agent: OAI-SearchBot +User-agent: omgili +User-agent: omgilibot +User-agent: OpenAI +User-agent: Operator +User-agent: PanguBot +User-agent: Panscient +User-agent: panscient.com +User-agent: Perplexity-User +User-agent: PerplexityBot +User-agent: PetalBot +User-agent: PhindBot +User-agent: Poggio-Citations +User-agent: Poseidon Research Crawler +User-agent: QualifiedBot +User-agent: QuillBot +User-agent: quillbot.com +User-agent: SBIntuitionsBot +User-agent: Scrapy +User-agent: SemrushBot-OCOB +User-agent: SemrushBot-SWA +User-agent: ShapBot +User-agent: Sidetrade indexer bot +User-agent: Spider +User-agent: TavilyBot +User-agent: TerraCotta +User-agent: Thinkbot +User-agent: TikTokSpider +User-agent: Timpibot +User-agent: TwinAgent +User-agent: VelenPublicWebCrawler +User-agent: WARDBot +User-agent: Webzio-Extended +User-agent: webzio-extended +User-agent: wpbot +User-agent: WRTNBot +User-agent: YaK +User-agent: YandexAdditional +User-agent: YandexAdditionalBot +User-agent: YouBot +User-agent: ZanistaBot +Disallow: / From a7676d06b6cbebea7dc44924717c54645f0e6fb4 Mon Sep 17 00:00:00 2001 From: Leyla Becker Date: Wed, 11 Feb 2026 15:51:26 -0600 Subject: [PATCH 06/10] feat: added site map --- .gitignore | 1 + _data/site.js | 7 +++++++ eleventy.config.js | 2 ++ flake.nix | 11 +++++++++-- nix/configuration.nix | 6 +----- nix/module.nix | 37 ++++++++++++++++++++++++------------- nix/package.nix | 3 ++- post-redirects.njk | 1 + sitemap.njk | 15 +++++++++++++++ 9 files changed, 62 insertions(+), 21 deletions(-) create mode 100644 _data/site.js create mode 100644 sitemap.njk diff --git a/.gitignore b/.gitignore index b4b4347..1c9d475 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ _site # nix packages .direnv +result # Environment variables .env diff --git a/_data/site.js b/_data/site.js new file mode 100644 index 0000000..e214bbe --- /dev/null +++ b/_data/site.js @@ -0,0 +1,7 @@ +module.exports = { + // Set SITE_URL environment variable to build for different domains: + // SITE_URL=https://blog.jan-leila.com pnpm run build + // SITE_URL=https://volpe.jan-leila.com pnpm run build + // SITE_URL=http://your-onion-address.onion pnpm run build + url: process.env.SITE_URL || "http://localhost:8080" +}; \ No newline at end of file diff --git a/eleventy.config.js b/eleventy.config.js index b8668db..f1d7345 100644 --- a/eleventy.config.js +++ b/eleventy.config.js @@ -223,6 +223,8 @@ module.exports = (eleventyConfig) => { eleventyConfig.addPassthroughCopy("css"); eleventyConfig.addPassthroughCopy("robots.txt"); + eleventyConfig.ignores.add("README.md"); + return { dir: { input: ".", diff --git a/flake.nix b/flake.nix index 47d9e3b..00aa531 100644 --- a/flake.nix +++ b/flake.nix @@ -20,8 +20,15 @@ }); in { packages = forEachSupportedSystem ({pkgs}: { - default = pkgs.callPackage ./nix/package.nix {}; - volpe = pkgs.callPackage ./nix/package.nix {}; + default = pkgs.callPackage ./nix/package.nix { + siteUrl = "https://blog.jan-leila.com"; + }; + blog = pkgs.callPackage ./nix/package.nix { + siteUrl = "https://blog.jan-leila.com"; + }; + volpe = pkgs.callPackage ./nix/package.nix { + siteUrl = "https://volpe.jan-leila.com"; + }; }); devShells = forEachSupportedSystem ({pkgs}: { diff --git a/nix/configuration.nix b/nix/configuration.nix index bdc5787..8ec82a3 100644 --- a/nix/configuration.nix +++ b/nix/configuration.nix @@ -1,8 +1,4 @@ -{ - config, - pkgs, - ... -}: { +{...}: { imports = [ ./hardware-configuration.nix ./module.nix diff --git a/nix/module.nix b/nix/module.nix index c71a02b..2ddc24b 100644 --- a/nix/module.nix +++ b/nix/module.nix @@ -5,21 +5,35 @@ ... }: let cfg = config.services.volpe; - pkg = pkgs.callPackage ./package.nix {}; + + mkPkg = domain: + pkgs.callPackage ./package.nix { + siteUrl = "https://${domain}"; + }; + + allDomains = [cfg.domain] ++ cfg.extraDomains; + + mkVirtualHost = domain: { + root = "${mkPkg domain}"; + forceSSL = cfg.enableACME; + enableACME = cfg.enableACME; + locations."/" = { + tryFiles = "$uri $uri/ /index.html"; + }; + }; in { options.services.volpe = { enable = lib.mkEnableOption "volpe blog"; domain = lib.mkOption { type = lib.types.str; - default = "localhost"; description = "Primary domain name for nginx virtual host."; }; extraDomains = lib.mkOption { type = lib.types.listOf lib.types.str; default = []; - description = "Additional domain names (aliases) for the virtual host."; + description = "Additional domain names, each gets its own virtualHost."; }; enableACME = lib.mkOption { @@ -43,15 +57,12 @@ in { recommendedGzipSettings = true; recommendedProxySettings = true; - virtualHosts.${cfg.domain} = { - root = "${pkg}"; - serverAliases = cfg.extraDomains; - forceSSL = cfg.enableACME; - enableACME = cfg.enableACME; - locations."/" = { - tryFiles = "$uri $uri/ /index.html"; - }; - }; + # Create a virtualHost for each domain + virtualHosts = lib.listToAttrs (map (domain: { + name = domain; + value = mkVirtualHost domain; + }) + allDomains); }; security.acme = lib.mkIf cfg.enableACME { @@ -61,4 +72,4 @@ in { networking.firewall.allowedTCPPorts = [80 443]; }; -} \ No newline at end of file +} diff --git a/nix/package.nix b/nix/package.nix index ace602e..cc122ef 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -5,6 +5,7 @@ pnpm_10, fetchPnpmDeps, pnpmConfigHook, + siteUrl, }: let nodejs = nodejs_latest; pnpm = pnpm_10; @@ -31,7 +32,7 @@ in buildPhase = '' runHook preBuild - pnpm build + SITE_URL="${siteUrl}" pnpm build runHook postBuild ''; diff --git a/post-redirects.njk b/post-redirects.njk index d4c29ea..eb6f8cb 100644 --- a/post-redirects.njk +++ b/post-redirects.njk @@ -6,6 +6,7 @@ pagination: resolve: keys permalink: /post/{{ slugData }}/ layout: base.njk +excludeFromSitemap: true --- {% set posts = collections.postsBySlug[slugData] %} diff --git a/sitemap.njk b/sitemap.njk new file mode 100644 index 0000000..9d4582f --- /dev/null +++ b/sitemap.njk @@ -0,0 +1,15 @@ +--- +permalink: /sitemap.xml +eleventyExcludeFromCollections: true +--- + + + {%- for page in collections.all %} + {%- if page.url and page.url != "/sitemap.xml" and not page.data.excludeFromSitemap %} + + {{ site.url }}{{ page.url }} + {{ (page.data.updatedAt or page.data.createdAt or page.date) | isoDate }} + + {%- endif %} + {%- endfor %} + \ No newline at end of file From 642ee3b45a8fb10f70c835c615938c749b7821ca Mon Sep 17 00:00:00 2001 From: Leyla Becker Date: Wed, 11 Feb 2026 16:08:51 -0600 Subject: [PATCH 07/10] feat: added cache for css --- _includes/base.njk | 39 ++++++++++++++++++++++++++++++++++-- eleventy.config.js | 49 +++++++++++++++++++++++++++++++++++++++++++++- nix/module.nix | 8 ++++++++ 3 files changed, 93 insertions(+), 3 deletions(-) diff --git a/_includes/base.njk b/_includes/base.njk index a1186f7..d94be0d 100644 --- a/_includes/base.njk +++ b/_includes/base.njk @@ -4,8 +4,43 @@ {{ title }} | Volpe - - + + {# Critical CSS inlined for faster initial render #} + + + {# Preload full stylesheet with cache-busted filename #} + + + + {# Defer prism.css - only needed for syntax highlighting #} + + +
diff --git a/eleventy.config.js b/eleventy.config.js index f1d7345..6bf9b09 100644 --- a/eleventy.config.js +++ b/eleventy.config.js @@ -4,8 +4,26 @@ const markdownItFootnote = require("markdown-it-footnote"); const markdownItMermaid = require('markdown-it-mermaid').default const syntaxHighlight = require("@11ty/eleventy-plugin-syntaxhighlight"); const fs = require("fs"); +const crypto = require("crypto"); +const path = require("path"); const { DateTime } = require("luxon"); +const cssHashCache = {}; +const getCssHash = (cssFile) => { + if (cssHashCache[cssFile]) return cssHashCache[cssFile]; + + const cssPath = path.join(__dirname, "css", cssFile); + try { + const content = fs.readFileSync(cssPath, "utf-8"); + const hash = crypto.createHash("md5").update(content).digest("hex").slice(0, 8); + cssHashCache[cssFile] = hash; + return hash; + } catch (e) { + console.warn(`Could not hash CSS file: ${cssFile}`); + return null; + } +}; + const extractTags = (content, mdInstance) => { if (!content) return []; @@ -220,7 +238,36 @@ module.exports = (eleventyConfig) => { return tagMap; }); - eleventyConfig.addPassthroughCopy("css"); + // Cache busting filter: returns hashed CSS filename + eleventyConfig.addFilter("cssHash", (cssFile) => { + const hash = getCssHash(cssFile); + const ext = path.extname(cssFile); + const base = path.basename(cssFile, ext); + return `/css/${base}.${hash}${ext}`; + }); + + eleventyConfig.on("eleventy.before", async () => { + const cssDir = path.join(__dirname, "css"); + const outputCssDir = path.join(__dirname, "_site", "css"); + + if (!fs.existsSync(outputCssDir)) { + fs.mkdirSync(outputCssDir, { recursive: true }); + } + + const cssFiles = fs.readdirSync(cssDir).filter(f => f.endsWith(".css")); + for (const cssFile of cssFiles) { + const hash = getCssHash(cssFile); + const ext = path.extname(cssFile); + const base = path.basename(cssFile, ext); + const hashedName = `${base}${hash == null ? '' : `.${hash}`}${ext}`; + + fs.copyFileSync( + path.join(cssDir, cssFile), + path.join(outputCssDir, hashedName) + ); + } + }); + eleventyConfig.addPassthroughCopy("robots.txt"); eleventyConfig.ignores.add("README.md"); diff --git a/nix/module.nix b/nix/module.nix index 2ddc24b..796dc2d 100644 --- a/nix/module.nix +++ b/nix/module.nix @@ -20,6 +20,14 @@ locations."/" = { tryFiles = "$uri $uri/ /index.html"; }; + # Cache static assets (CSS, JS, images) for 1 year with immutable + locations."~* \\.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$" = { + extraConfig = '' + expires 1y; + add_header Cache-Control "public, max-age=31536000, immutable"; + access_log off; + ''; + }; }; in { options.services.volpe = { From 3970f98dcd788f5b264011c6f90628889882d393 Mon Sep 17 00:00:00 2001 From: Leyla Becker Date: Wed, 11 Feb 2026 16:24:53 -0600 Subject: [PATCH 08/10] feat: added page metadata --- _includes/base.njk | 5 ++++- index.njk | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/_includes/base.njk b/_includes/base.njk index d94be0d..4376df2 100644 --- a/_includes/base.njk +++ b/_includes/base.njk @@ -3,7 +3,10 @@ - {{ title }} | Volpe + Volpe{% if title %} | {{ title }}{% endif %} + {% if description %} + + {% endif %} {# Critical CSS inlined for faster initial render #}