{"title":"Development vs Deployment Architecture","description":"Understanding how MyLittleContentEngine works across development, build, and production phases","islands":{"content":"\u003Cheader class=\u0022transition-all mb-4 lg:mb-8\u0022\u003E\u003Ch1 class=\u0022font-display text-2xl lg:text-4xl font-bold tracking-tight text-base-900 dark:text-base-50\u0022\u003EDevelopment vs Deployment Architecture\u003C/h1\u003E\u003C/header\u003E\n\n\u003Cmain class=\u0022prose dark:prose-invert dark:text-base-300 max-w-full prose-sm md:prose-base min-w-0 prose-headings:scroll-m-18 prose-headings:font-display prose-headings:text-base-900 dark:prose-headings:text-base-50\u0022\u003E\u003Cp\u003EMyLittleContentEngine operates in three distinct phases, each with different architectural characteristics. Understanding these phases is essential for effectively developing and deploying your content sites.\u003C/p\u003E\n\u003Ch2 id=\u0022the-three-phases\u0022\u003EThe Three Phases\u003C/h2\u003E\n\u003Cp\u003EMyLittleContentEngine is a \u003Cstrong\u003Ehybrid static site generator\u003C/strong\u003E that uses Blazor Server-Side Rendering (SSR) as its rendering engine. This unique approach provides the best of both worlds: a rich development experience with hot reload capabilities, and a fully static output for production deployment.\u003C/p\u003E\n\u003Cp\u003EThe three phases are:\u003C/p\u003E\n\u003Col\u003E\n\u003Cli\u003E\u003Cstrong\u003EDevelopment Mode\u003C/strong\u003E - Running your site locally with \u003Ccode\u003Edotnet run\u003C/code\u003E or \u003Ccode\u003Edotnet watch\u003C/code\u003E\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003EBuild/Generation Phase\u003C/strong\u003E - Generating static files with \u003Ccode\u003Edotnet run -- build\u003C/code\u003E\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003EProduction Serving\u003C/strong\u003E - Hosting the generated static files\u003C/li\u003E\n\u003C/ol\u003E\n\u003Ch2 id=\u0022development-mode\u0022\u003EDevelopment Mode\u003C/h2\u003E\n\u003Cp\u003EWhen you run your application with \u003Ccode\u003Edotnet run\u003C/code\u003E or \u003Ccode\u003Edotnet watch\u003C/code\u003E, MyLittleContentEngine operates as a standard ASP.NET Core web application with Blazor SSR.\u003C/p\u003E\n\u003Ch3 id=\u0022how-it-works\u0022\u003EHow It Works\u003C/h3\u003E\n\u003Cp\u003EYour application starts a web server that handles requests dynamically. When a user (or you during development) requests a page:\u003C/p\u003E\n\u003Col\u003E\n\u003Cli\u003EThe ASP.NET Core routing system matches the URL to a Blazor component\u003C/li\u003E\n\u003Cli\u003EThe component requests content from the appropriate \u003Ccode\u003EIContentService\u003C/code\u003E implementation\u003C/li\u003E\n\u003Cli\u003EThe content service lazily loads and caches content in memory\u003C/li\u003E\n\u003Cli\u003EThe Blazor component renders the content as HTML\u003C/li\u003E\n\u003Cli\u003EThe response is sent to the browser\u003C/li\u003E\n\u003C/ol\u003E\n\u003Ch3 id=\u0022content-service-behavior\u0022\u003EContent Service Behavior\u003C/h3\u003E\n\u003Cp\u003EContent services like \u003Ccode\u003EMarkdownContentService\u003C/code\u003E use lazy loading with caching:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Cstrong\u003EOn first request\u003C/strong\u003E: The service processes all content files (e.g., all markdown files) and builds an in-memory index\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003ESubsequent requests\u003C/strong\u003E: Content is served from the cache, making responses very fast\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003EOn file changes\u003C/strong\u003E: The file watcher invalidates the cache, triggering a fresh reload on the next request\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003EThis caching strategy provides excellent performance while keeping content always up-to-date during development.\u003C/p\u003E\n\u003Ch3 id=\u0022hot-reload\u0022\u003EHot Reload\u003C/h3\u003E\n\u003Cp\u003EMyLittleContentEngine includes a sophisticated hot reload system:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EFile watchers monitor your content directories for changes\u003C/li\u003E\n\u003Cli\u003EWhen a file changes (e.g., you save a markdown file), the system invalidates the cached content\u003C/li\u003E\n\u003Cli\u003EThe next page request triggers a complete reprocessing of content\u003C/li\u003E\n\u003Cli\u003EYour browser sees the updated content immediately\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003EThis enables a smooth development workflow where you can edit content and see changes instantly.\u003C/p\u003E\n\u003Ch3 id=\u0022static-assets\u0022\u003EStatic Assets\u003C/h3\u003E\n\u003Cp\u003EDuring development, static assets are served directly from their source locations:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EFiles in \u003Ccode\u003Ewwwroot/\u003C/code\u003E\u003C/li\u003E\n\u003Cli\u003EContent directory assets (images, downloads, etc.)\u003C/li\u003E\n\u003Cli\u003ERazor Class Library assets (like \u003Ccode\u003Escripts.js\u003C/code\u003E from MyLittleContentEngine.UI)\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003EAll assets are served dynamically through middleware, allowing you to modify them and see changes immediately.\u003C/p\u003E\n\u003Ch2 id=\u0022buildgeneration-phase\u0022\u003EBuild/Generation Phase\u003C/h2\u003E\n\u003Cp\u003EWhen you run \u003Ccode\u003Edotnet run -- build\u003C/code\u003E, MyLittleContentEngine switches from dynamic serving to static site generation.\u003C/p\u003E\n\u003Ch3 id=\u0022how-it-works-1\u0022\u003EHow It Works\u003C/h3\u003E\n\u003Cp\u003EThe generation process follows these steps:\u003C/p\u003E\n\u003Col\u003E\n\u003Cli\u003E\u003Cstrong\u003ETemporary Server Start\u003C/strong\u003E: A web server starts temporarily (just like in development mode)\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003EPage Collection\u003C/strong\u003E: The \u003Ccode\u003EOutputGenerationService\u003C/code\u003E asks all registered content services for their pages via \u003Ccode\u003EIContentService.GetPagesToGenerateAsync()\u003C/code\u003E\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003EOutput Preparation\u003C/strong\u003E: The output directory is cleared and recreated\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003EAsset Collection\u003C/strong\u003E: Static assets are collected from all sources via \u003Ccode\u003EIContentService.GetContentToCopyAsync()\u003C/code\u003E\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003EPage Generation\u003C/strong\u003E: Each page is rendered by making HTTP requests to the temporary server\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003EServer Shutdown\u003C/strong\u003E: The temporary server stops, leaving only static files\u003C/li\u003E\n\u003C/ol\u003E\n\u003Ch3 id=\u0022the-role-of-icontentservice\u0022\u003EThe Role of IContentService\u003C/h3\u003E\n\u003Cp\u003EDuring generation, \u003Ccode\u003EIContentService\u003C/code\u003E implementations play a crucial role:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Cp\u003E\u003Cstrong\u003E\u003Ccode\u003EGetPagesToGenerateAsync()\u003C/code\u003E\u003C/strong\u003E: Returns a list of all pages to render\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Ccode\u003EMarkdownContentService\u003C/code\u003E returns one page per markdown file, plus tag pages\u003C/li\u003E\n\u003Cli\u003E\u003Ccode\u003EApiReferenceContentService\u003C/code\u003E returns pages for namespaces, types, etc.\u003C/li\u003E\n\u003Cli\u003ECustom content services can contribute their own pages\u003C/li\u003E\n\u003C/ul\u003E\n\u003C/li\u003E\n\u003Cli\u003E\u003Cp\u003E\u003Cstrong\u003E\u003Ccode\u003EGetContentToCopyAsync()\u003C/code\u003E\u003C/strong\u003E: Returns static assets to copy\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EImage files, downloads, or other resources that don\u0027t need rendering\u003C/li\u003E\n\u003C/ul\u003E\n\u003C/li\u003E\n\u003Cli\u003E\u003Cp\u003E\u003Cstrong\u003E\u003Ccode\u003EGetContentToCreateAsync()\u003C/code\u003E\u003C/strong\u003E: Returns dynamically generated files\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003ESitemap.xml, RSS feeds, search indexes, etc.\u003C/li\u003E\n\u003C/ul\u003E\n\u003C/li\u003E\n\u003C/ul\u003E\n\u003Ch3 id=\u0022priority-based-generation\u0022\u003EPriority-Based Generation\u003C/h3\u003E\n\u003Cp\u003EPages are generated in priority order to handle dependencies:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Cstrong\u003EMustBeFirst\u003C/strong\u003E (0): Pages that other pages depend on\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003ENormal\u003C/strong\u003E (50): Standard content pages\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003EMustBeLast\u003C/strong\u003E (100): Pages that depend on other generated content (like CSS files that scan HTML)\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003EWithin each priority level, pages are generated in parallel for optimal performance.\u003C/p\u003E\n\u003Ch3 id=\u0022the-http-trick\u0022\u003EThe HTTP Trick\u003C/h3\u003E\n\u003Cp\u003EThe generation process uses a clever technique: it makes HTTP requests to the running application, just as a browser would. This means:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EPages are rendered using exactly the same code path as development\u003C/li\u003E\n\u003Cli\u003ENo duplicate rendering logic is needed\u003C/li\u003E\n\u003Cli\u003EThe generated HTML is exactly what users would see if you ran the site dynamically\u003C/li\u003E\n\u003C/ul\u003E\n\u003Ch2 id=\u0022production-serving\u0022\u003EProduction Serving\u003C/h2\u003E\n\u003Cp\u003EAfter generation completes, you have a folder full of static HTML files and assets that can be deployed anywhere.\u003C/p\u003E\n\u003Ch3 id=\u0022what-gets-generated\u0022\u003EWhat Gets Generated\u003C/h3\u003E\n\u003Cp\u003EThe output directory contains:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Cstrong\u003EHTML files\u003C/strong\u003E: One file per page (e.g., \u003Ccode\u003Eblog/my-post.html\u003C/code\u003E)\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003EStatic assets\u003C/strong\u003E: JavaScript, CSS, images, downloads\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003EGenerated files\u003C/strong\u003E: Sitemap, RSS feed, search index\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003EDirectory structure\u003C/strong\u003E: Mirrors your URL structure\u003C/li\u003E\n\u003C/ul\u003E\n\u003Ch3 id=\u0022how-it-differs-from-development\u0022\u003EHow It Differs from Development\u003C/h3\u003E\n\u003Cp\u003EThe generated HTML has been transformed:\u003C/p\u003E\n\u003Col\u003E\n\u003Cli\u003E\u003Cstrong\u003ECross-references resolved\u003C/strong\u003E: \u003Ccode\u003E\u0026lt;xref:some.uid\u0026gt;\u003C/code\u003E links are converted to proper \u003Ccode\u003E\u0026lt;a\u0026gt;\u003C/code\u003E tags\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003EBase URLs applied\u003C/strong\u003E: If you built with a base path (e.g., \u003Ccode\u003E/my-blog/\u003C/code\u003E), all URLs are rewritten\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003ENo server required\u003C/strong\u003E: Everything is baked into the HTML\u003C/li\u003E\n\u003C/ol\u003E\n\u003Ch3 id=\u0022hosting-requirements\u0022\u003EHosting Requirements\u003C/h3\u003E\n\u003Cp\u003EThe static output can be hosted on any static file server:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EGitHub Pages\u003C/li\u003E\n\u003Cli\u003ENetlify\u003C/li\u003E\n\u003Cli\u003EAzure Static Web Apps\u003C/li\u003E\n\u003Cli\u003EAny web server (nginx, Apache, IIS)\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003EThe only requirement is that the host can serve HTML files and handle routing (e.g., serving \u003Ccode\u003E/about.html\u003C/code\u003E when \u003Ccode\u003E/about\u003C/code\u003E is requested). Most modern static hosts handle this automatically.\u003C/p\u003E\n\u003Ch2 id=\u0022complete-walkthrough-example\u0022\u003EComplete Walkthrough Example\u003C/h2\u003E\n\u003Cp\u003ELet\u0027s follow a blog post through all three phases to see how everything connects.\u003C/p\u003E\n\u003Ch3 id=\u0022phase-1-development\u0022\u003EPhase 1: Development\u003C/h3\u003E\n\u003Cp\u003EYou create a new markdown file:\u003C/p\u003E\n\u003Cdiv class=\u0022code-highlight-wrapper not-prose\u0022\u003E\n\u003Cdiv class=\u0022standalone-code-container\u0022\u003E\n\u003Cdiv class=\u0022standalone-code-highlight\u0022\u003E\n\u003Cpre\u003E\u003Ccode\u003E---\n\u003Cspan class=\u0022hljs-tag\u0022\u003Et\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003Eitle\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E:\u003C/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003EMy First Blog Post\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\n\u003Cspan class=\u0022hljs-tag\u0022\u003Ed\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003Eescription\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E:\u003C/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003ELearning how MyLittleContentEngine works\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\n\u003Cspan class=\u0022hljs-tag\u0022\u003Eu\u003C/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003Eid\u003C/span\u003E\u003Cspan class=\u0022hljs-punctuation\u0022\u003E:\u003C/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003Eblog.first-post\u003C/span\u003E\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\u003C/span\u003E\n---\n\n\u003Cspan class=\u0022hljs-punctuation\u0022\u003E#\u003C/span\u003E \u003Cspan class=\u0022hljs-name\u0022\u003EMy First Blog Post\u003C/span\u003E\n\nThis is my first post using MyLittleContentEngine!\u003C/code\u003E\u003C/pre\u003E\n\u003C/div\u003E\n\u003C/div\u003E\n\u003C/div\u003E\n\n\u003Cp\u003E\u003Cstrong\u003EWhat happens:\u003C/strong\u003E\u003C/p\u003E\n\u003Col\u003E\n\u003Cli\u003EYou save \u003Ccode\u003EContent/blog/my-first-post.md\u003C/code\u003E\u003C/li\u003E\n\u003Cli\u003EThe file watcher detects the change and invalidates the \u003Ccode\u003EMarkdownContentService\u003C/code\u003E cache\u003C/li\u003E\n\u003Cli\u003EYou navigate to \u003Ccode\u003Ehttp://localhost:5000/blog/my-first-post\u003C/code\u003E in your browser\u003C/li\u003E\n\u003Cli\u003EThe Blazor routing matches the URL to a content page component\u003C/li\u003E\n\u003Cli\u003EThe component calls \u003Ccode\u003EMarkdownContentService.GetRenderedContentPageByUrlOrDefault(\u0022/blog/my-first-post\u0022)\u003C/code\u003E\u003C/li\u003E\n\u003Cli\u003ESince the cache was invalidated, the service:\n\u003Cul\u003E\n\u003Cli\u003EScans all markdown files in the content directory\u003C/li\u003E\n\u003Cli\u003EFinds your new file and processes it\u003C/li\u003E\n\u003Cli\u003EParses the front matter\u003C/li\u003E\n\u003Cli\u003EConverts markdown to HTML\u003C/li\u003E\n\u003Cli\u003EStores the result in memory\u003C/li\u003E\n\u003C/ul\u003E\n\u003C/li\u003E\n\u003Cli\u003EThe component receives the rendered HTML and displays it\u003C/li\u003E\n\u003Cli\u003EThe browser shows your blog post\u003C/li\u003E\n\u003C/ol\u003E\n\u003Cp\u003E\u003Cstrong\u003ESubsequent visits\u003C/strong\u003E to this page (or any other page) use the cached content until you modify a file again.\u003C/p\u003E\n\u003Ch3 id=\u0022phase-2-build\u0022\u003EPhase 2: Build\u003C/h3\u003E\n\u003Cp\u003EYou\u0027re ready to deploy, so you run:\u003C/p\u003E\n\u003Cdiv class=\u0022code-highlight-wrapper not-prose\u0022\u003E\n\u003Cdiv class=\u0022standalone-code-container\u0022\u003E\n\u003Cdiv class=\u0022standalone-code-highlight\u0022\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u003Cspan class=\u0022line\u0022\u003E\u003Cspan class=\u0022hljs-built_in\u0022\u003Edotnet\u003C/span\u003E run \u003Cspan class=\u0022hljs-params\u0022\u003E--\u003C/span\u003E build \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022/\u0022\u003C/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022output\u0022\u003C/span\u003E\u003C/span\u003E\n\u003C/code\u003E\u003C/pre\u003E\n\u003C/div\u003E\n\u003C/div\u003E\n\u003C/div\u003E\n\n\u003Cp\u003E\u003Cstrong\u003EWhat happens:\u003C/strong\u003E\u003C/p\u003E\n\u003Col\u003E\n\u003Cli\u003EThe application starts a temporary web server on a random port\u003C/li\u003E\n\u003Cli\u003E\u003Ccode\u003EOutputGenerationService\u003C/code\u003E calls \u003Ccode\u003EMarkdownContentService.GetPagesToGenerateAsync()\u003C/code\u003E\u003C/li\u003E\n\u003Cli\u003EThe markdown service processes all files (including your blog post) and returns:\n\u003Cul\u003E\n\u003Cli\u003EA page entry for \u003Ccode\u003E/blog/my-first-post\u003C/code\u003E\u003C/li\u003E\n\u003Cli\u003EPages for any other markdown files\u003C/li\u003E\n\u003Cli\u003EPages for tag listings\u003C/li\u003E\n\u003C/ul\u003E\n\u003C/li\u003E\n\u003Cli\u003EThe service also calls \u003Ccode\u003EGetContentToCopyAsync()\u003C/code\u003E to find images and other assets\u003C/li\u003E\n\u003Cli\u003EFor your blog post, the generator:\n\u003Cul\u003E\n\u003Cli\u003EMakes an HTTP GET request to \u003Ccode\u003Ehttp://localhost:[port]/blog/my-first-post\u003C/code\u003E\u003C/li\u003E\n\u003Cli\u003EThe server renders it (same as development)\u003C/li\u003E\n\u003Cli\u003ESaves the HTML to \u003Ccode\u003Eoutput/blog/my-first-post.html\u003C/code\u003E\u003C/li\u003E\n\u003C/ul\u003E\n\u003C/li\u003E\n\u003Cli\u003EAll other pages are generated in parallel\u003C/li\u003E\n\u003Cli\u003EStatic assets are copied to the output directory\u003C/li\u003E\n\u003Cli\u003EThe temporary server shuts down\u003C/li\u003E\n\u003C/ol\u003E\n\u003Ch3 id=\u0022phase-3-production\u0022\u003EPhase 3: Production\u003C/h3\u003E\n\u003Cp\u003EYou deploy the \u003Ccode\u003Eoutput/\u003C/code\u003E folder to your hosting service.\u003C/p\u003E\n\u003Cp\u003E\u003Cstrong\u003EWhat happens:\u003C/strong\u003E\u003C/p\u003E\n\u003Col\u003E\n\u003Cli\u003EA user navigates to \u003Ccode\u003Ehttps://yourdomain.com/blog/my-first-post\u003C/code\u003E\u003C/li\u003E\n\u003Cli\u003EThe static file host serves \u003Ccode\u003Eblog/my-first-post.html\u003C/code\u003E\u003C/li\u003E\n\u003Cli\u003EThe browser receives pure HTML (no server-side processing)\u003C/li\u003E\n\u003Cli\u003EClient-side JavaScript enhances the page with interactive features\u003C/li\u003E\n\u003Cli\u003EThe user sees your blog post\u003C/li\u003E\n\u003C/ol\u003E\n\u003Cp\u003E\u003Cstrong\u003EKey differences from development:\u003C/strong\u003E\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003ENo ASP.NET Core server running\u003C/li\u003E\n\u003Cli\u003ENo content services executing\u003C/li\u003E\n\u003Cli\u003ENo dynamic rendering\u003C/li\u003E\n\u003Cli\u003EJust static files being served by a basic web server\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003EIf you need to update the blog post, you edit the markdown file and rebuild. The development workflow stays the same; only the final deployment changes.\u003C/p\u003E\n\u003Ch2 id=\u0022key-differences-summary\u0022\u003EKey Differences Summary\u003C/h2\u003E\n\u003Ctable\u003E\n\u003Cthead\u003E\n\u003Ctr\u003E\n\u003Cth\u003EAspect\u003C/th\u003E\n\u003Cth\u003EDevelopment Mode\u003C/th\u003E\n\u003Cth\u003EBuild Phase\u003C/th\u003E\n\u003Cth\u003EProduction Serving\u003C/th\u003E\n\u003C/tr\u003E\n\u003C/thead\u003E\n\u003Ctbody\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Cstrong\u003ERuntime\u003C/strong\u003E\u003C/td\u003E\n\u003Ctd\u003EASP.NET Core \u002B Blazor SSR\u003C/td\u003E\n\u003Ctd\u003ETemporary server for generation\u003C/td\u003E\n\u003Ctd\u003EStatic file host\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Cstrong\u003EContent Processing\u003C/strong\u003E\u003C/td\u003E\n\u003Ctd\u003ELazy load \u002B cache, reprocess on file changes\u003C/td\u003E\n\u003Ctd\u003EAll content processed once\u003C/td\u003E\n\u003Ctd\u003EN/A (pre-rendered)\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Cstrong\u003EIContentService Role\u003C/strong\u003E\u003C/td\u003E\n\u003Ctd\u003EServes content dynamically from cache\u003C/td\u003E\n\u003Ctd\u003EProvides lists of pages and assets to generate\u003C/td\u003E\n\u003Ctd\u003ENot present\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Cstrong\u003EHot Reload\u003C/strong\u003E\u003C/td\u003E\n\u003Ctd\u003EFile watching invalidates cache\u003C/td\u003E\n\u003Ctd\u003ENot applicable\u003C/td\u003E\n\u003Ctd\u003ENot applicable\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Cstrong\u003EResponse Time\u003C/strong\u003E\u003C/td\u003E\n\u003Ctd\u003EFast (from cache) after warmup\u003C/td\u003E\n\u003Ctd\u003EN/A\u003C/td\u003E\n\u003Ctd\u003EInstant (static files)\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Cstrong\u003EURL Handling\u003C/strong\u003E\u003C/td\u003E\n\u003Ctd\u003ERuntime routing and middleware\u003C/td\u003E\n\u003Ctd\u003EBaked into generated HTML\u003C/td\u003E\n\u003Ctd\u003EHost serves static files\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Cstrong\u003EResource Usage\u003C/strong\u003E\u003C/td\u003E\n\u003Ctd\u003EMemory for caching content\u003C/td\u003E\n\u003Ctd\u003ETemporary (during generation only)\u003C/td\u003E\n\u003Ctd\u003EMinimal (just file serving)\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Cstrong\u003EWhen to Use\u003C/strong\u003E\u003C/td\u003E\n\u003Ctd\u003ELocal development and testing\u003C/td\u003E\n\u003Ctd\u003EBefore deployment\u003C/td\u003E\n\u003Ctd\u003EEnd-user access\u003C/td\u003E\n\u003C/tr\u003E\n\u003C/tbody\u003E\n\u003C/table\u003E\n\u003Ch2 id=\u0022understanding-the-hybrid-approach\u0022\u003EUnderstanding the Hybrid Approach\u003C/h2\u003E\n\u003Cp\u003EMyLittleContentEngine\u0027s architecture provides several advantages:\u003C/p\u003E\n\u003Cp\u003E\u003Cstrong\u003EFor Developers:\u003C/strong\u003E\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EFamiliar ASP.NET development experience\u003C/li\u003E\n\u003Cli\u003EInstant feedback with hot reload\u003C/li\u003E\n\u003Cli\u003EFull debugging capabilities during development\u003C/li\u003E\n\u003Cli\u003EContent services work the same way in development and build\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003E\u003Cstrong\u003EFor Users:\u003C/strong\u003E\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EFast page loads (static HTML)\u003C/li\u003E\n\u003Cli\u003ENo server-side dependencies\u003C/li\u003E\n\u003Cli\u003EWorks on any static hosting platform\u003C/li\u003E\n\u003Cli\u003EExcellent performance and reliability\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003E\u003Cstrong\u003EFor Content:\u003C/strong\u003E\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003ESingle source of truth (your markdown files, API metadata, etc.)\u003C/li\u003E\n\u003Cli\u003EContent services define how content is processed\u003C/li\u003E\n\u003Cli\u003ESame rendering logic in development and production\u003C/li\u003E\n\u003Cli\u003EExtensible through custom \u003Ccode\u003EIContentService\u003C/code\u003E implementations\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003EThis hybrid approach makes MyLittleContentEngine unique among static site generators: you develop with the full power of a web framework, but deploy with the simplicity of static files.\u003C/p\u003E\n\u003C/main\u003E\u003Cdiv class=\u0022flex my-12 border-t border-base-200 dark:border-base-700 pt-4 lg:pt-8\u0022\u003E\u003Cdiv class=\u0022flex flex-col items-start  gap-3\u0022\u003E\u003Ca class=\u0022inline-flex gap-0.5 justify-center overflow-hidden text-sm font-medium font-display transition rounded-xl bg-base-200 pt-1.5 pb-1 px-3 lg:pt-2 lg:pb.15 lg:px-4 hover:bg-base-300/75 dark:bg-base-800/40 text-base-800 dark:text-base-400 ring-1 dark:ring-inset ring-base-300/75 dark:ring-base-800 dark:hover:bg-base-800 dark:hover:text-base-300\u0022 aria-label=\u0022Previous: Adding SPA Navigation\u0022 href=\u0022/MyLittleContentEngine/guides/adding-spa-navigation/\u0022\u003E\u003Cspan class=\u0022-ml-1 rotate-180\u0022\u003E\u003Csvg viewBox=\u00220 0 20 20\u0022 fill=\u0022none\u0022 aria-hidden=\u0022true\u0022 class=\u0022mt-0.5 h-5 w-5\u0022\u003E\u003Cpath stroke=\u0022currentColor\u0022 stroke-linecap=\u0022round\u0022 stroke-linejoin=\u0022round\u0022 d=\u0022m11.5 6.5 3 3.5m0 0-3 3.5m3-3.5h-9\u0022\u003E\u003C/path\u003E\u003C/svg\u003E\u003C/span\u003E Previous\u003C/a\u003E\n            \u003Ca tabindex=\u0022-1\u0022 aria-hidden=\u0022true\u0022 class=\u0022text-sm lg:text-base font-semibold text-base-700 transition hover:text-base-600 dark:text-base-400 dark:hover:text-base-300\u0022 href=\u0022/MyLittleContentEngine/guides/adding-spa-navigation/\u0022\u003EAdding SPA Navigation\u003C/a\u003E\u003C/div\u003E\u003Cdiv class=\u0022flex flex-col items-end ml-auto gap-3\u0022\u003E\u003Ca class=\u0022inline-flex gap-0.5 justify-center overflow-hidden text-sm font-medium font-display transition rounded-xl bg-base-200 pt-1.5 pb-1 px-3 lg:pt-2 lg:pb.15 lg:px-4 hover:bg-base-300/75 dark:bg-base-800/40 text-base-800 dark:text-base-400 ring-1 dark:ring-inset ring-base-300/75 dark:ring-base-800 dark:hover:bg-base-800 dark:hover:text-base-300\u0022 aria-label=\u0022Next: Hot Reload Architecture\u0022 href=\u0022/MyLittleContentEngine/under-the-hood/hot-reload-architecture/\u0022\u003ENext \u003Cspan class=\u0022-mr-1\u0022\u003E\u003Csvg viewBox=\u00220 0 20 20\u0022 fill=\u0022none\u0022 aria-hidden=\u0022true\u0022 class=\u0022mt-0.5 h-5 w-5\u0022\u003E\u003Cpath stroke=\u0022currentColor\u0022 stroke-linecap=\u0022round\u0022 stroke-linejoin=\u0022round\u0022 d=\u0022m11.5 6.5 3 3.5m0 0-3 3.5m3-3.5h-9\u0022\u003E\u003C/path\u003E\u003C/svg\u003E\u003C/span\u003E\u003C/a\u003E\n            \u003Ca tabindex=\u0022-1\u0022 aria-hidden=\u0022true\u0022 class=\u0022text-sm lg:text-base font-semibold text-base-700 transition hover:text-base-600 dark:text-base-400 dark:hover:text-base-300\u0022 href=\u0022/MyLittleContentEngine/under-the-hood/hot-reload-architecture/\u0022\u003EHot Reload Architecture\u003C/a\u003E\u003C/div\u003E\u003C/div\u003E"}}