Skip to main content
Home

Built and signed on GitHub Actions

a no-build TypeScript fullstack SSR-first framework for developing fast web applications with a shallow learning curve

This package works with Cloudflare Workers, Node.js, Deno, Bun
This package works with Cloudflare Workers
This package works with Node.js
This package works with Deno
This package works with Bun
JSR Score
100%
Published
2 months ago (0.18.0)

FullSoak

JSR JSR Score Built with the Deno Standard Library codecov GitHub Repo stars Discord

FullS(tack)oak (FullSoak for short) is a modern (born 2025), no-build TypeScript fullstack framework for building fast web applications with a shallow learning curve. At its core is the Oak http server framework which is inspired by Koa (one of the popular Node.js http frameworks).

Key Differentiators

  1. FullSoak is no-build [1]. Zero, zip, zilch, nada. That means: no tsc nor webpack. All files are served from where they are. No surprises. Still, optimizations such as minification and mangling are supported.

  2. FullSoak supports both JSX and HTM (Hyperscript Tagged Markup) which boasts several enhancements over JSX - but most importantly: both require no separate build step (back to point 1). JSX transformation is automatically applied on a per-file basis.

  3. FullSoak is Preact. So: the familiarity of React, but as lean as we need it to be.

  4. FullSoak is SSR-first & SSR-optimized. See Deno's explanation on JSX precompile for more details.

  5. FullSoak is (mostly) WYSIWYG. Compared to sophisticated frameworks such as Next.js, or Remix, or Deno's Fresh, FullSoak is intended to be quite "feature-poor": 1) you start with a "Controller" file (as in good old "MVC") which 2) renders your TSX component as text/html content (i.e. a plain string), and then 3) the content hydrates itself on the client side. For isomorphic use cases, there're no "special-purpose functions" to remember: where & how to write data fetching logic is left entirely at the disposal of the developer.

Example usage

As with most frameworks, fullsoak recommends a certain directory structure. Here's a bare-minimum example for Deno runtime:

Prerequisite: Deno

fullsoak-example
|_ src
|  |_ components
|  |  |_ Shared
|  |  |  |_ styles.css
|  |  |_ MyComponent
|  |     |_ index.tsx
|  |     |_ styles.css
|  |_ main.ts
|_ deno.jsonc
// deno.jsonc
{
  "imports": {
    "fullsoak": "jsr:@fullsoak/fullsoak@0.18.0",
    "preact": "npm:preact@10.26.5"
  },
  "nodeModulesDir": "auto",
  "compilerOptions": {
    // see https://docs.deno.com/runtime/reference/jsx/#jsx-precompile-transform
    "jsx": "precompile",
    "jsxImportSource": "preact",
    "jsxPrecompileSkipElements": ["a", "link"]
  }
}
// src/main.ts
import { Controller, Get, ssr, useFullSoak } from "fullsoak";
import { MyComponent } from "./components/MyComponent/index.tsx";

@Controller()
class MyController {
  @Get("/")
  index() {
    return ssr(MyComponent);
  }
}

const port = 3991;

useFullSoak({ port, controllers: [MyController] });
// src/components/MyComponent/index.tsx
import type { FunctionComponent } from "preact";
export const MyComponent: FunctionComponent = () => <div>hello, world</div>;
/* src/components/MyComponent/styles.css */
@import "/components/Shared/styles.css";

Then the app can be started up for local development:

deno -A --watch src/main.ts

or simply served directly on production and/or inside a Docker container:

# please supply the Deno security permissions flags to your desire
# https://docs.deno.com/runtime/fundamentals/security/#permissions
deno src/main.ts

Route-aware Isomorphic Components

Rendering route-aware isomorphic components is supported via preact-iso. See examples:

Live Demo / Projects using FullSoak

Trade-offs

Build step, while imposing additional cognitive loads & occasionally hindering a good Developer Experience, has its own benefits. Without build (bundling) step, the optimizations (e.g. resource loaders in build-time or run-time) have to be provisioned in other manners. The high-level wish is to use as much standard web specs as possible (think preload, prefetch, etc.) to make up for what's sacrified by dropping the build step.

Besides, more benchmarks are needed on small & large scale codebases across different use cases (e.g. MPA blog site vs rich-interactive SPA vs even large E-Commerce site) to get an understanding of how feasible / scalable this approach is, and for which scenarios.

Further Reading


[1] no bundle

Built and signed on
GitHub Actions

New Ticket: Report package

Please provide a reason for reporting this package. We will review your report and take appropriate action.

Please review the JSR usage policy before submitting a report.

Add Package

deno add jsr:@fullsoak/fullsoak

Import symbol

import * as fullsoak from "@fullsoak/fullsoak";
or

Import directly with a jsr specifier

import * as fullsoak from "jsr:@fullsoak/fullsoak";

Add Package

pnpm i jsr:@fullsoak/fullsoak
or (using pnpm 10.8 or older)
pnpm dlx jsr add @fullsoak/fullsoak

Import symbol

import * as fullsoak from "@fullsoak/fullsoak";

Add Package

yarn add jsr:@fullsoak/fullsoak
or (using Yarn 4.8 or older)
yarn dlx jsr add @fullsoak/fullsoak

Import symbol

import * as fullsoak from "@fullsoak/fullsoak";

Add Package

vlt install jsr:@fullsoak/fullsoak

Import symbol

import * as fullsoak from "@fullsoak/fullsoak";

Add Package

npx jsr add @fullsoak/fullsoak

Import symbol

import * as fullsoak from "@fullsoak/fullsoak";

Add Package

bunx jsr add @fullsoak/fullsoak

Import symbol

import * as fullsoak from "@fullsoak/fullsoak";