SSR framework for Svelte 5 + Bun with islands-based selective hydration
Tailwind
Drive Tailwind v4 with its Node API — no PostCSS, no Vite. Mochi ships an opt-in helper at mochi-framework/tailwind that compiles your input CSS at server startup and re-runs on file changes in dev. Then import the generated file from any .svelte and Mochi’s CSS-import bundler links it scoped to the page.
Install Tailwind alongside its standalone Node + scanner packages (mochi-framework is already in your project; the Tailwind packages are optional peers):
bun add tailwindcss @tailwindcss/node @tailwindcss/oxideWrite an input CSS that imports the layers you want and tells Tailwind where to scan:
/* src/styles/app.css */
@import 'tailwindcss/theme.css' layer(theme);
@import 'tailwindcss/utilities.css' layer(utilities);
@source './*.svelte';
/* Preflight is skipped above. If your host shell already ships an unlayered
universal reset (`*, *::before, *::after { margin: 0; padding: 0 }`), add
element-level resets here for tags whose UA defaults you care about. */
button {
appearance: none;
background: transparent;
border: 0;
font: inherit;
color: inherit;
cursor: pointer;
}Call setupTailwind before Mochi.serve():
// src/index.ts
import { setupTailwind } from 'mochi-framework/tailwind';
await setupTailwind({
input: './src/styles/app.css',
output: './src/styles/app.generated.css',
minify: process.env.MODE !== 'development',
});Then import the generated file from any .svelte that uses Tailwind classes:
<script>
import '../styles/app.generated.css';
</script>
<button class="rounded-md bg-emerald-600 px-3 py-1.5 text-white hover:bg-emerald-700"> Click </button>The framework strips the import from the JS bundle and serves the CSS at /_mochi/import-css/<hash>.css. The <link> is added to the <head> of every page that transitively imports it — pages that don’t use Tailwind don’t pay for it.
In dev, setupTailwind subscribes to Mochi’s file watcher and rebuilds on .svelte / .ts / .css changes; the resulting .css write goes through Mochi’s CSS fast-path (no full SSR rebuild) and the page reloads.
Add app.generated.css to .gitignore — it’s a build artifact.