Skip to content
rshono
Documentation menu

Advanced

Styling & assets

Native CSS code-split per route, the four lines that add Tailwind, and public/.

Import a stylesheet from any component:

import './styles.css';

Rspack's native CSS pipeline compiles it, and the import attaches the stylesheet to the importing page's assets. CSS is therefore code-split per route and <link>ed in the streamed HTML rather than fetched after hydration. *.module.css gets a class map.

No PostCSS in the framework

Not as a dependency, not as an optional one. Native CSS is everything a plain stylesheet needs — but that parser reads finished CSS, and @import 'tailwindcss', @theme and @apply are not that. A stylesheet that needs a plugin brings the plugin itself, through the rspack hook.

Tailwind

Four things, and npx @rshono/create@latest --tailwind writes all of them:

Package manager
npm i -D tailwindcss @tailwindcss/postcss postcss postcss-loader
pnpm add -D tailwindcss @tailwindcss/postcss postcss postcss-loader
yarn add -D tailwindcss @tailwindcss/postcss postcss postcss-loader
bun add --dev tailwindcss @tailwindcss/postcss postcss postcss-loader
// rshono.config.ts — the hook is called once per compiler, so this reaches both graphs
export default defineConfig({
  rspack(config) {
    config.module!.rules!.push({ test: /\.css$/i, use: ['postcss-loader'], type: 'css/auto' });
  },
});
// postcss.config.mjs — the plugin list, which postcss-loader finds on its own
export default { plugins: { '@tailwindcss/postcss': {} } };
/* src/styles.css */
@import 'tailwindcss';

Keep type: 'css/auto' rather than 'css', or *.module.css stops being a CSS module. Any other PostCSS plugin is the same shape — the rule puts postcss-loader in the chain, postcss.config.mjs says which plugins run.

public/

Anything in public/ is served verbatim at the web root, and copied into dist/ by the build:

public/favicon.ico       →  /favicon.ico
public/robots.txt        →  /robots.txt
public/.well-known/…     →  /.well-known/…

It is a fallback: routes always win, and unmatched paths still reach the notFound page, so a public/ file never shadows a route.

Caching

What Served from Caching
Hashed bundle output /_static/ long-lived, immutable
public/ files web root short max-age (no-cache in dev)

A bundle filename contains its content hash, so it can be cached forever. public/favicon.svg is the same URL whatever its contents, so it cannot. On a platform with a CDN both go straight to the CDN; prerendered pages do not.