Global styles#
The baseline, and the one every other approach sits on top of: a plain CSS file at src/styles.css.
/* src/styles.css */
:root {
--brand: #0062ff;
--line: #e2e8f0;
}
body {
margin: 0;
font: 16px/1.6 ui-sans-serif, system-ui, sans-serif;
}
.card {
padding: 1.25rem;
border: 1px solid var(--line);
border-radius: 1rem;
}There is nothing to import and nothing to register. The file is found by name, bundled by Vite, and linked once in the server-rendered shell:
<link rel="stylesheet" id="jx-style-0" href="/styles.css">It is a bundler entry, not a copied file#
The stylesheet always goes through the bundler, even when it contains no preprocessor syntax at all. That is what makes these work:
@import "@janux/tailwind"; /* a bare specifier from node_modules */
@import "./theme/typography.css"; /* a relative partial */
.hero {
background: url('./assets/hero.avif'); /* rewritten and hashed */
}Copying the file verbatim would ship all three as literal text the browser cannot resolve. Because it is an entry, @import of a dependency's CSS, bare specifiers and url() assets resolve exactly as they did in dev.
Assets that are not CSS#
Anything in public/ is copied to the output as-is and served from the root — fonts, images, favicons:
public/
favicon.svg → /favicon.svg
fonts/inter.woff2 → /fonts/inter.woff2@font-face {
font-family: 'Inter';
src: url('/fonts/inter.woff2') format('woff2');
font-display: swap;
}Use public/ for files whose URL you want to control. Use a relative url() from the stylesheet for everything the bundler should hash and fingerprint.
Inlining the sheet#
For a small stylesheet, the <link> is an extra round trip before first paint. inlineStyles embeds the built CSS in the document instead:
// janux.config.ts
export default { inlineStyles: true };This is a production-only switch: janux dev keeps the <link> so CSS hot reload keeps working. It reads back the sheet the build just emitted, so before the first janux build the shell simply falls back to the link.
Inlining is a win while the CSS is small enough to be cheaper than a request, and a loss once it is big enough to be worth caching separately across pages.
No stylesheet at all#
The entry is optional. An app with no src/styles.css gets no <link> and no CSS asset — which, combined with a page that has no islands, is how a Janux page ships 0 KB of both CSS and JS.