Frugal

A web framework that wastes not

Static by default

By default Frugal only produces static html at build time, working like a static site generator.

Each static page will be rebuilt only if the underlying data or code changed. If you use Frugal as a server, static page can also be generated just in time (on the first request), or regenerated via webhook.

With a good content strategy you don't need to redeploy when your content changes

static-page.ts
import { DataResponse } from "http://deno.land/x/frugal/mod.ts"
                        
export const route = '/';

export function generate() {
    return new DataResponse({
        data: {
            hello: 'world'
        }
    });
}

export function render({ data }) {
    return `<html>
        <body>
            <h1>Hello ${data.hello} !</h1>
        </body>
    </html>`;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

Server side rendering when needed

Frugal comes with a server that can render dynamic pages at request time. Pages can answer to GET, POST, PUT and DELETE with fully controlable responses (status and headers).

dynamic-page.ts
import { DataResponse } from "http://deno.land/x/frugal/mod.ts"
                        
export const route = '/:id';
    
export const type = 'dynamic'

export async function GET({ path }) {
    return new DataResponse({
        data: {
            post: await getPostById(path.id)
        }
    });
}

export function render({ data }) {
    return `<html>
        <body>
            <h1>${data.post.title}</h1>
            ${data.post.content}
        </body>
    </html>`;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

Progressive enhancement via scripts

Any module declared as script will be bundled and executed in the browser, allowing you to add interactivity to your pages where you need it.

Clients that can run those scripts will get an enhanced experience, those that can't will get a functional html page.

Those "scripts" are the building blocks for island hydration if you use a client-side UI framework.

import { DataResponse } from "http://deno.land/x/frugal/mod.ts"
import './log.script.ts'
                        
export const route = '/';

export function generate() {
    return new DataResponse({
        data: {
            hello: 'world'
        }
    });
}

export function render({ data }) {
    return `<html>
        <body>
            <h1>Hello ${data.hello} !</h1>
        </body>
    </html>`;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Island hydration

Based on scripts, Frugal implements an integration with Preact and Svelte. You can describe the whole UI with thoses framework, and optionnaly declare island of interactivity that will be bundled, served and hydrated on the client.

If you want to use another UI framework, integrations with Frugal via scripts should be easy to write.

This is an interactive island

It was hydrated on the client with an initial value of 5 supplied by the server
5
import { DataResponse, } from "http://deno.land/x/frugal/page.ts"
import { getRenderFrom } from "http://deno.land/x/frugal/runtime/preact.server.ts"
import { Page } from "./Page.tsx";

export const route = '/';

export function generate() {
    return new DataResponse({
        data: {
            hello: 'world'
        }
    });
}

export const render = getRenderFrom(Page)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15