@md/cf-page

An opinionated, HTML-close web framework for creating Cloudflare Pages with full local development support.

Getting Started

Ensure you have Deno installed and then run:

deno run -A jsr:@md/cf-page init

This will:

Features

⚡ TypeScript Transpilation & Bundling

Automatic TypeScript compilation with full bundling support using Deno's native bundler.

Features:

  • Automatic TypeScript to JavaScript transpilation
  • Module bundling with dependency resolution using data URI encoding
  • Minification enabled automatically in production builds
  • Support for both local and remote imports (JSR, npm, HTTP)
  • Type checking during build process
  • Self-contained builds with base64 encoded dependencies

How it works:

  • Transpilation: TypeScript files are compiled to modern JavaScript
  • Bundling: All dependencies are resolved and bundled into a single file
  • Remote imports: External dependencies are fetched and included in the bundle
  • Production optimization: Automatic minification reduces file size for production builds

Example

// src/main.ts
import { serve } from "https://deno.land/std/http/server.ts";
import { helper } from "./utils.ts";

export default function() {
  return helper("Hello TypeScript!");
}

This TypeScript file will be automatically transpiled, bundled with its dependencies, and served as optimized JavaScript.

🎨 Tailwind CSS

Built-in Tailwind CSS 4 support for utility-first styling. See the Tailwind documentation for complete class reference and usage patterns.

Features:

  • Tailwind CSS 4 integration
  • Automatic class detection and purging
  • Custom component layers support
  • Dark mode variants

🗜️ File Minification

Intelligent file optimization that automatically reduces file sizes in production builds while preserving functionality and maintaining development-friendly source code.

Production-Only Minification:

  • CSS: PostCSS with cssnano plugin for optimal compression
  • JavaScript: Built-in minification via Deno's bundler
  • TypeScript: Compiled and minified during bundling process

CSS Minification Details:

  • Removes unnecessary whitespace and comments
  • Optimizes CSS rules and declarations
  • Merges identical selectors and rules
  • Shortens color values and units where possible
  • Only runs in production builds to maintain readable development code

JavaScript Minification:

  • Variable name shortening and code compression
  • Dead code elimination removes unused functions
  • Integrated with the bundling process for optimal results
  • Preserves source functionality while reducing bundle size

Development vs Production

// Development: Readable, unminified code
.header {
  background-color: #ffffff;
  padding: 1rem 2rem;
}

// Production: Minified and optimized
.header{background:#fff;padding:1rem 2rem}

Minification only occurs during production builds, keeping your development experience fast and debuggable.

🔄 Automatic Cache-Busting

Intelligent cache-busting system that automatically adds version parameters to asset URLs, ensuring users always receive the latest versions while enabling aggressive browser caching.

Supported Elements:

  • Scripts: <script src="..."> tags
  • Stylesheets: <link rel="stylesheet"> tags
  • Images: <img src="..."> tags
  • Media: <video>, <audio>, <source>, <track> elements

Hash Generation Process:

  • Content-based hashing using file contents for accuracy
  • Base64URL encoding for URL-safe hash values
  • Handles relative (`./`, `../`) and absolute (`/`) paths
  • Only processes local assets, skips external URLs
  • Rehype plugin integration for reliable HTML processing

Before and After

<!-- Before cache-busting -->
<link rel="stylesheet" href="/style.css">
<script src="./main.js"></script>
<img src="../images/logo.png" alt="Logo">

<!-- After cache-busting -->
<link rel="stylesheet" href="/style.css?v=abc123def456">
<script src="./main.js?v=xyz789uvw012"></script>
<img src="../images/logo.png?v=mno345pqr678" alt="Logo">

Query parameters are automatically added based on file content hashes. When files change, new hashes ensure cache invalidation.

Benefits:

  • Aggressive Caching: Set long cache headers without fear of stale content
  • Instant Updates: Content changes immediately invalidate caches
  • CDN Optimization: Perfect compatibility with CDN caching strategies
  • Zero Configuration: Works automatically on all supported asset types

📄 Compile-time HTML Templating

Advanced slot-based templating system with layout inheritance that processes templates at build time, ensuring zero runtime overhead and optimal performance.

Core Features:

  • Layout Inheritance: Hierarchical +layout.html files
  • Named Slots: Content injection with <slot name="...">
  • Default Content: Fallback content when slots aren't filled
  • Directory-based: Automatic layout discovery walking up the file tree
  • Compile-time Processing: Templates resolved during build, not runtime

Layout Structure Example

<!-- src/+layout.html -->
<!DOCTYPE html>
<html>
<head>
  <title><slot name="title">Default Title</slot></title>
</head>
<body>
  <header><slot name="header"></slot></header>
  <main><slot>Default main content</slot></main>
  <footer><slot name="footer">© {cf:year}</slot></footer>
</body>
</html>

Page Content Example

<!-- src/about/index.html -->
<slot name="title">About Us</slot>
<slot name="header">
  <nav><a href="/">Home</a></nav>
</slot>

<h1>About Our Company</h1>
<p>This content goes into the default slot.</p>

How it Works:

  • Layout Discovery: Walks up directory tree to find nearest +layout.html
  • String Processing: Processes templates before HTML parsing to preserve structure
  • Slot Injection: Replaces elements with matching content
  • Default Handling: Uses slot default content when no replacement is provided
  • Build-time Resolution: All templates fully resolved during build process

Benefits:

  • Zero Runtime Cost: Templates compiled away during build
  • SEO Friendly: Generates complete, static HTML files
  • Maintainable: Shared layouts reduce code duplication
  • Flexible: Named slots allow precise content placement

🌍 Translation Engine

Built-in multi-language support with YAML translation files, parameter interpolation, and conditional rendering capabilities.

Features:

  • YAML-based translation files (+lang.yml)
  • Parameter interpolation with flexible syntax
  • Markdown support: Use {@md key} directive for formatted content
  • Conditional rendering: {#if condition} and {#else} blocks
  • Array iteration: {#each array as item} loops
  • Cascading translation override system
  • Auto-detection of supported languages from root +lang.yml
  • Global and page-specific translations
  • Configuration via $defaultLanguage key in language files
  • Multi-language Build: Generates separate versions for each language (e.g., /en/, /de/)

Parameter Syntax

Translation values can include parameters that are replaced at build time. The syntax supports multiple parameter types:

<!-- Basic syntax: {key, param1: value1, param2: value2} -->

<!-- String literal parameters -->
<h1>{greeting, name: "John Doe"}</h1>
<!-- Output: Hello John Doe! -->

<!-- Translation key references -->
<h1>{welcome, name: {siteName}}</h1>
<!-- Output: Welcome to My Site! -->

<!-- Nested translation keys -->
<footer>{footer.copyright, year: {cf:year}}</footer>
<!-- Output: Copyright © 2025 mdressler. All rights reserved. -->

<!-- Mixed parameter types -->
<p>{message, user: {userName}, time: "10:30 AM", date: {cf:year}}</p>
<!-- Output: User John Doe logged in at 10:30 AM on 2025 -->

<!-- Built-in variables -->
<div lang="{cf:lang}">{cf:path}</div>
<!-- Output: <div lang="en">/about.html</div> -->

Parameter Types:

  • String literals: Enclosed in double quotes: "value"
  • Translation keys: Enclosed in braces: {key} or {nested.key}
  • Built-in variables: {cf:lang} (current language), {cf:path} (current path), {cf:year} (current year)

More Parameter Examples

The parameter syntax is flexible and supports complex use cases:

<!-- Language file with nested structure -->
# src/+lang.yml
en:
  messages:
    greeting: "Hello {user}, welcome to {app}!"
  footer:
    copyright: "© {year} {company}. All rights reserved."
  products:
    price: "${amount} USD"
    
<!-- Using nested keys with parameters -->
<h1>{messages.greeting, user: "Alice", app: {siteName}}</h1>
<!-- Output: Hello Alice, welcome to My Site! -->

<!-- Multiple levels of nesting -->
<footer>{footer.copyright, year: {cf:year}, company: "ACME Corp"}</footer>
<!-- Output: © 2025 ACME Corp. All rights reserved. -->

<!-- Combining with conditionals -->
{#if isOnSale}
  <span class="price">{products.price, amount: "49.99"}</span>
{#else}
  <span class="price">{products.price, amount: "99.99"}</span>
{/if}

Conditional & Loop Syntax

Use conditional blocks and loops to show or hide content and iterate over arrays:

<!-- Conditional rendering based on translation values -->
{#if userLoggedIn}
  <p>Welcome back, {userName}!</p>
  <a href="/logout">Logout</a>
{#else}
  <p>Please log in to continue.</p>
  <a href="/login">Login</a>
{/if}

<!-- Array iteration with markdown support -->
{#each menuItems as item}
  <li>
    <a href="/{item}">{navigation[item]}</a>
    <!-- Use @md directive to process markdown in array items -->
    <p>{@md item} section with [additional info](/{item}/info)</p>
  </li>
{/each}

<!-- Conditional content based on feature flags -->
{#if featureEnabled}
  <div class="new-feature">
    <h3>🎉 New Feature Available!</h3>
    <p>{newFeatureDescription}</p>
  </div>
{/if}

Note: Conditional blocks work with any translation key that resolves to a truthy/falsy value. Loop blocks work with arrays. To enable markdown processing within these blocks, use the {@md key} directive (see Markdown Processing section below).

Language Files

Create a +lang.yml file in your source directory to define languages and translations:

# src/+lang.yml
$defaultLanguage: en

global:
  siteName: "My Site"
  userLoggedIn: false
  featureEnabled: true
  menuItems: ["home", "about", "contact"]

en:
  welcome: "Welcome to {name}!"
  userName: "John Doe"
  newFeatureDescription: "Try our new dashboard with enhanced analytics!"
  navigation:
    home: "Home"
    about: "About"
    contact: "Contact"

de:
  welcome: "Willkommen bei {name}!"
  userName: "Johann Müller"
  newFeatureDescription: "Probieren Sie unser neues Dashboard mit erweiterten Analysen!"
  navigation:
    home: "Startseite"
    about: "Über uns"
    contact: "Kontakt"

Markdown Processing

Process markdown-formatted content from translation values using the {@md key} directive:

<!-- Language file content -->
# src/+lang.yml
en:
  boldText: "This is **very important**"
  linkText: "Visit [our website](https://example.com)"
  codeExample: "Use the `npm install` command"
  richContent: "This has **bold** and `code` and [links](/) all together"

<!-- HTML template -->
<!-- Regular placeholders - markdown NOT processed -->
<p>{boldText}</p>  
<!-- Outputs: This is **very important** -->

<!-- Markdown directive - markdown IS processed -->
<p>{@md boldText}</p>  
<!-- Outputs: This is <strong>very important</strong> -->

<p>{@md linkText}</p>
<!-- Outputs: Visit <a href="https://example.com">our website</a> -->

<p>Command: {@md codeExample}</p>
<!-- Outputs: Command: Use the <code>npm install</code> command -->

<div>{@md richContent}</div>
<!-- Outputs: This has <strong>bold</strong> and <code>code</code> and <a href="/">links</a> all together -->

Important: Markdown processing only occurs when using the {@md key} directive. Regular translation placeholders like {key} will output raw markdown text without processing. This explicit approach gives you full control over when markdown formatting is applied.

Using Translations in HTML

<!-- src/index.html -->
<h1>{welcome, name: {siteName}}</h1>

<!-- Conditional user interface -->
{#if userLoggedIn}
  <p>Welcome back, {userName}!</p>
  <a href="/logout">Logout</a>
{#else}
  <p>Please log in to continue.</p>
  <a href="/login">Login</a>
{/if}

<!-- Dynamic navigation with arrays -->
<nav>
  <ul>
    {#each menuItems as item}
      <li>
        <a href="/{item}">{navigation[item]}</a>
        <!-- Use @md directive to process markdown formatting -->
        <small>{@md item} section</small>
      </li>
    {/each}
  </ul>
</nav>

<!-- Feature flag example -->
{#if featureEnabled}
  <div class="feature-banner">
    <h3>🎉 New Feature Available!</h3>
    <p>{newFeatureDescription}</p>
  </div>
{/if}

🖼️ Automatic Image Optimization

Intelligent image processing for optimal web delivery without quality loss.

Optimizations:

  • Lossless PNG compression
  • JPG quality optimization
  • SVG minification and cleaning
  • Automatic format selection

📦 Inline Assets

Inline external resources directly into your HTML for reduced HTTP requests and faster page loads.

Inline Capabilities:

  • SVG Images: <img inline src="logo.svg" /> - Inlines SVG as inline SVG element
  • Scripts: <script inline src="script.js"></script> - Inlines JavaScript content
  • Stylesheets: <link inline rel="stylesheet" href="style.css" /> - Inlines CSS as