Development vs Deployment Architecture
MyLittleContentEngine operates in three distinct phases, each with different architectural characteristics. Understanding these phases is essential for effectively developing and deploying your content sites.
The Three Phases
MyLittleContentEngine is a hybrid static site generator 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.
The three phases are:
- Development Mode - Running your site locally with
dotnet runordotnet watch - Build/Generation Phase - Generating static files with
dotnet run -- build - Production Serving - Hosting the generated static files
Development Mode
When you run your application with dotnet run or dotnet watch, MyLittleContentEngine operates as a standard ASP.NET Core web application with Blazor SSR.
How It Works
Your application starts a web server that handles requests dynamically. When a user (or you during development) requests a page:
- The ASP.NET Core routing system matches the URL to a Blazor component
- The component requests content from the appropriate
IContentServiceimplementation - The content service lazily loads and caches content in memory
- The Blazor component renders the content as HTML
- The response is sent to the browser
Content Service Behavior
Content services like MarkdownContentService use lazy loading with caching:
- On first request: The service processes all content files (e.g., all markdown files) and builds an in-memory index
- Subsequent requests: Content is served from the cache, making responses very fast
- On file changes: The file watcher invalidates the cache, triggering a fresh reload on the next request
This caching strategy provides excellent performance while keeping content always up-to-date during development.
Hot Reload
MyLittleContentEngine includes a sophisticated hot reload system:
- File watchers monitor your content directories for changes
- When a file changes (e.g., you save a markdown file), the system invalidates the cached content
- The next page request triggers a complete reprocessing of content
- Your browser sees the updated content immediately
This enables a smooth development workflow where you can edit content and see changes instantly.
Static Assets
During development, static assets are served directly from their source locations:
- Files in
wwwroot/ - Content directory assets (images, downloads, etc.)
- Razor Class Library assets (like
scripts.jsfrom MyLittleContentEngine.UI)
All assets are served dynamically through middleware, allowing you to modify them and see changes immediately.
Build/Generation Phase
When you run dotnet run -- build, MyLittleContentEngine switches from dynamic serving to static site generation.
How It Works
The generation process follows these steps:
- Temporary Server Start: A web server starts temporarily (just like in development mode)
- Page Collection: The
OutputGenerationServiceasks all registered content services for their pages viaIContentService.GetPagesToGenerateAsync() - Output Preparation: The output directory is cleared and recreated
- Asset Collection: Static assets are collected from all sources via
IContentService.GetContentToCopyAsync() - Page Generation: Each page is rendered by making HTTP requests to the temporary server
- Server Shutdown: The temporary server stops, leaving only static files
The Role of IContentService
During generation, IContentService implementations play a crucial role:
GetPagesToGenerateAsync(): Returns a list of all pages to renderMarkdownContentServicereturns one page per markdown file, plus tag pagesApiReferenceContentServicereturns pages for namespaces, types, etc.- Custom content services can contribute their own pages
GetContentToCopyAsync(): Returns static assets to copy- Image files, downloads, or other resources that don't need rendering
GetContentToCreateAsync(): Returns dynamically generated files- Sitemap.xml, RSS feeds, search indexes, etc.
Priority-Based Generation
Pages are generated in priority order to handle dependencies:
- MustBeFirst (0): Pages that other pages depend on
- Normal (50): Standard content pages
- MustBeLast (100): Pages that depend on other generated content (like CSS files that scan HTML)
Within each priority level, pages are generated in parallel for optimal performance.
The HTTP Trick
The generation process uses a clever technique: it makes HTTP requests to the running application, just as a browser would. This means:
- Pages are rendered using exactly the same code path as development
- No duplicate rendering logic is needed
- The generated HTML is exactly what users would see if you ran the site dynamically
Production Serving
After generation completes, you have a folder full of static HTML files and assets that can be deployed anywhere.
What Gets Generated
The output directory contains:
- HTML files: One file per page (e.g.,
blog/my-post.html) - Static assets: JavaScript, CSS, images, downloads
- Generated files: Sitemap, RSS feed, search index
- Directory structure: Mirrors your URL structure
How It Differs from Development
The generated HTML has been transformed:
- Cross-references resolved:
<xref:some.uid>links are converted to proper<a>tags - Base URLs applied: If you built with a base path (e.g.,
/my-blog/), all URLs are rewritten - No server required: Everything is baked into the HTML
Hosting Requirements
The static output can be hosted on any static file server:
- GitHub Pages
- Netlify
- Azure Static Web Apps
- Any web server (nginx, Apache, IIS)
The only requirement is that the host can serve HTML files and handle routing (e.g., serving /about.html when /about is requested). Most modern static hosts handle this automatically.
Complete Walkthrough Example
Let's follow a blog post through all three phases to see how everything connects.
Phase 1: Development
You create a new markdown file:
---
title: "My First Blog Post"
description: "Learning how MyLittleContentEngine works"
uid: "blog.first-post"
---
# My First Blog Post
This is my first post using MyLittleContentEngine!
What happens:
- You save
Content/blog/my-first-post.md - The file watcher detects the change and invalidates the
MarkdownContentServicecache - You navigate to
http://localhost:5000/blog/my-first-postin your browser - The Blazor routing matches the URL to a content page component
- The component calls
MarkdownContentService.GetRenderedContentPageByUrlOrDefault("/blog/my-first-post") - Since the cache was invalidated, the service:
- Scans all markdown files in the content directory
- Finds your new file and processes it
- Parses the front matter
- Converts markdown to HTML
- Stores the result in memory
- The component receives the rendered HTML and displays it
- The browser shows your blog post
Subsequent visits to this page (or any other page) use the cached content until you modify a file again.
Phase 2: Build
You're ready to deploy, so you run:
dotnet run -- build "/" "output"
What happens:
- The application starts a temporary web server on a random port
OutputGenerationServicecallsMarkdownContentService.GetPagesToGenerateAsync()- The markdown service processes all files (including your blog post) and returns:
- A page entry for
/blog/my-first-post - Pages for any other markdown files
- Pages for tag listings
- A page entry for
- The service also calls
GetContentToCopyAsync()to find images and other assets - For your blog post, the generator:
- Makes an HTTP GET request to
http://localhost:[port]/blog/my-first-post - The server renders it (same as development)
- Saves the HTML to
output/blog/my-first-post.html
- Makes an HTTP GET request to
- All other pages are generated in parallel
- Static assets are copied to the output directory
- The temporary server shuts down
Phase 3: Production
You deploy the output/ folder to your hosting service.
What happens:
- A user navigates to
https://yourdomain.com/blog/my-first-post - The static file host serves
blog/my-first-post.html - The browser receives pure HTML (no server-side processing)
- Client-side JavaScript enhances the page with interactive features
- The user sees your blog post
Key differences from development:
- No ASP.NET Core server running
- No content services executing
- No dynamic rendering
- Just static files being served by a basic web server
If 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.
Key Differences Summary
| Aspect | Development Mode | Build Phase | Production Serving |
|---|---|---|---|
| Runtime | ASP.NET Core + Blazor SSR | Temporary server for generation | Static file host |
| Content Processing | Lazy load + cache, reprocess on file changes | All content processed once | N/A (pre-rendered) |
| IContentService Role | Serves content dynamically from cache | Provides lists of pages and assets to generate | Not present |
| Hot Reload | File watching invalidates cache | Not applicable | Not applicable |
| Response Time | Fast (from cache) after warmup | N/A | Instant (static files) |
| URL Handling | Runtime routing and middleware | Baked into generated HTML | Host serves static files |
| Resource Usage | Memory for caching content | Temporary (during generation only) | Minimal (just file serving) |
| When to Use | Local development and testing | Before deployment | End-user access |
Understanding the Hybrid Approach
MyLittleContentEngine's architecture provides several advantages:
For Developers:
- Familiar ASP.NET development experience
- Instant feedback with hot reload
- Full debugging capabilities during development
- Content services work the same way in development and build
For Users:
- Fast page loads (static HTML)
- No server-side dependencies
- Works on any static hosting platform
- Excellent performance and reliability
For Content:
- Single source of truth (your markdown files, API metadata, etc.)
- Content services define how content is processed
- Same rendering logic in development and production
- Extensible through custom
IContentServiceimplementations
This 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.