🍡 mochi

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/oxide

Write 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.