Fresh Web Framework

repository·main·Indexed 11 days ago

https://github.com/freshframework/fresh

A high-performance web framework built for Deno featuring an island-based architecture, zero runtime overhead by default, and native TypeScript support. It provides both file-system and programmatic routing, Ahead-of-Time (AOT) builds for optimized assets, and official plugins for Vite and Tailwind CSS.

Tokens
91.6K
Snippets
331
Records
411
Agent score
93%

What's inside Fresh

  1. What is Fresh?

    main

    Fresh is a full-stack modern web framework for JavaScript and TypeScript developers. It is designed to build high-quality, performant, and personalized web applications using a combination of a routing framework and a templating engine that renders pages on demand on the server.

    Key characteristics include:

    • Island Architecture: Server-rendered pages can contain specific areas (Islands) that are made interactive on the client.
    • Zero Config: No configuration is necessary to get started.
    • Tiny & Fast: The framework itself requires no client-side JavaScript.
    • Optional Hydration: Client-side hydration is applied only to individual components as needed.
    • Progressive Enhancement: Highly resilient through the use of native browser features.
    • TypeScript Support: TypeScript works out of the box.
    • File-system Routing: Uses a routing system similar to Next.js.
    • Rendering Engine: Uses Preact as the JSX rendering engine.
  2. Core features of Fresh

    main

    Fresh is a next-generation web framework designed for speed and simplicity. Key architectural features include:

    • Island-based client hydration: Only interactive components (islands) receive JavaScript, maximizing performance.
    • Zero runtime overhead: No JavaScript is shipped to the client by default.
    • No configuration: Works out of the box without complex setup.
    • TypeScript support: Native support for TypeScript.
    • File-system routing: Uses a file-system based routing pattern similar to Next.js.
  3. Advanced Fresh concepts

    main

    For more complex application structures, Fresh provides these advanced abstractions:

    • App wrapper: Manages the outer HTML structure, typically handling everything up to the <body> tag.
    • Layouts: Allows you to reuse shared UI structures when calling ctx.render() across different routes.
    • Partials: Enables streaming in server-generated content into the current page.
  4. Core concepts in Fresh

    main

    Fresh is built around several fundamental abstractions that manage the lifecycle of a web application:

    • Architecture: The flow of requests from middleware to islands.
    • App: The central object holding application information like routes.
    • Middleware: Functions that receive a request and return a Response. They can set headers or pass state. If a middleware returns a response without calling the next one, it acts as a handler.
    • Context: An object passed through every middleware used to share state, trigger redirects, or render HTML.
    • Routing: The mechanism that matches a URL to a specific chain of middlewares.
    • File Routing: A convention-based routing system driven by the filesystem structure.
    • Data Fetching: The process of loading data on the server to pass it to page components.
    • Islands: Interactive Preact components that are rendered on the client.
    • Signals: A reactive state management system used within islands.
    • Static Files: The system for serving assets like images and CSS.
  5. Understand the Fresh project structure

    main

    A Fresh project relies on several key files and directories to manage routing, interactivity, and deployment.

    Core Files

    • dev.ts: The development entry point used to start your project locally. While the name is conventional, it is the file you execute during development.
    • main.ts: The production entry point. This is the file you link to Deno Deploy for live hosting.
    • fresh.gen.ts: An automatically generated manifest file. It tracks your routes and islands based on the contents of your routes/ and islands/ folders. This file is updated during development.
    • deno.json: The project configuration file. It contains an imports field (an import map for dependency management) and defines the start task for running the development server.

    Core Directories

    • routes/: Contains your application's routes. The filename determines the URL path. Code in this folder runs only on the server and is never sent to the client.
    • islands/: Contains interactive components known as 'islands'. Code in this folder is executed on both the server and the client.
    • static/: Contains static assets (like images or CSS) that are served directly to the client without modification.
  6. What is an app wrapper and how to use it

    main

    An app wrapper provides a global structure (like <html>, <head>, and <body> tags) for your entire application. It is defined in a routes/_app.tsx file and must contain a single default export that is a Preact component. Only one app wrapper is allowed per application.

    When using a standard (synchronous) app wrapper, the component receives props of type PageProps. This includes a Component prop (the current route/layout being rendered) and a state prop, which contains any state set by middleware.

    import { PageProps } from "$fresh/server.ts";
    
    export default function App({ Component, state }: PageProps) {
      return (
        <html>
          <head>
            <meta charset="utf-8" />
            <title>My Fresh app</title>
          </head>
          <body>
            <Component />
          </body>
        </html>
      );
    }
  7. What is middleware in Fresh

    main

    A middleware is a function that intercepts a request and returns a response. It receives a Context object containing the Request.

    Middlewares are commonly used to:

    • Set HTTP Headers
    • Measure response times
    • Fetch data and pass it to subsequent middlewares or handlers via ctx.state
    • Implement access control or analytics

    Middlewares can be chained, allowing you to perform logic both before and after the next handler in the chain by awaiting ctx.next().

    const app = new App<{ greeting: string }>()
      .use((ctx) => {
        // Middleware to pass data via state
        ctx.state.greeting = "Hello world";
        return ctx.next();
      })
      .use(async (ctx) => {
        // Middleware to modify the response after the next handler
        const res = await ctx.next();
        res.headers.set("server", "fresh server");
        return res;
      })
      .get("/", (ctx) => {
        return ctx.render(<h1>{ctx.state.greeting}</h1>);
      });
  8. What is an app wrapper and when to use it

    main

    An app wrapper is the outermost component in Fresh's rendering hierarchy. It is rendered only on the server and defines the shared <html, <head>, and <body> tags for every page in your application.

    Use an app wrapper to:

    • Set the document language (e.g., <html lang="en">).
    • Include global <meta> tags, fonts, or stylesheets.
    • Add analytics scripts or structured data to every page.
    • Set a global <body> class or data attribute.
    • Provide a consistent HTML skeleton without repeating it in every layout.
  9. What is instrumented in Fresh with OpenTelemetry

    main

    Fresh provides built-in OpenTelemetry instrumentation that automatically creates spans under the fresh tracer (named with the current Fresh version). This allows you to trace the lifecycle of a request without manual code changes.

    Key instrumented operations include:

    • Middleware execution: Each middleware in the chain gets its own span.
    • Route handler execution: Spans for handler function calls.
    • Rendering: Server-side page rendering, including async components.
    • Static file serving: Spans for file lookups, caching, and responses.
    • Lazy route loading: Spans for dynamic imports of route modules on first access.

    The root span for every request includes the http.route attribute (e.g., GET /blog/:slug), which enables grouping traces by route pattern.

  10. Correlate server-side and client-side traces

    main

    When an OpenTelemetry exporter is active, Fresh automatically injects a W3C Trace Context <meta> tag into the <head> of every rendered page.

    This allows client-side instrumentation (like @opentelemetry/instrumentation-document-load) to link browser performance traces back to the specific server-side span that rendered the page, enabling end-to-end visibility.

    <head>
      <meta
        name="traceparent"
        content="00-ab42124a3c573678d4d8b21ba52df3bf-d21f7bc17caa5aba-01"
      >
      <!-- ... -->
    </head>
  11. How signals are serialized

    main

    Fresh provides special handling for @preact/signals:

    1. On the Server: The signal's current value is read via .peek() and serialized.
    2. On the Client: The value is wrapped in a new signal() call, creating a live reactive signal.

    Synchronization: If the same signal object is passed to multiple islands, they all receive the same signal instance on the client, keeping them synchronized.

    Computed Signals: These are serialized by reading their current value and wrapping it in computed(() => value) on the client. Note that because the original computation function cannot be transferred, the client-side computed signal holds a static value.