Next.js integration
// next.config.ts
import { withTracelessStyle } from "traceless-style/nextjs";
const nextConfig = {
// your existing config
};
export default withTracelessStyle(nextConfig);
That's the integration. withTracelessStyle():
- Adds the
tracelessStyleLoaderto webpack's module rules (transformstl.create/tl.extendcalls in.ts/.tsx/.js/.jsx). - Adds
TracelessStyleWebpackPluginto webpack's plugins:- On
beforeCompile: runs full extraction acrosssrcDir. - On
thisCompilation: injects__TRACELESS_STYLE_META__viaDefinePlugin. - On
afterEmit: re-emitspublic/traceless-style.css.
- On
- Configures Turbopack
resolveAlias(Windows-safe forward slashes). - Auto-injects
traceless-style.cssinto the client entry via a tiny shim. - Throws a clear error if
nextisn't resolvable in the consumer's project.
Options
withTracelessStyle(nextConfig, {
srcDir: "src",
variants: {
_tablet: "@media (min-width: 900px)",
},
});
| Option | Type | Default |
|---|---|---|
srcDir | string | union of src/ and app/ |
variants | Record<string, string> | none (use tl.extend instead, recommended) |
Root layout: anti-flash + style sheet
The integration auto-imports public/traceless-style.css, but you should still add <TracelessRoot /> to prevent FOUC for dark/RTL users:
// app/layout.tsx
import { TracelessRoot } from "traceless-style/dark";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<head>
<TracelessRoot />
</head>
<body>{children}</body>
</html>
);
}
<TracelessRoot /> renders an inline <script> that reads localStorage (saved theme + direction) and applies the matching classes/attributes to <html> before React hydrates. This eliminates the flash of light theme that single-page apps usually have on first load.
App Router vs Pages Router
withTracelessStyle works with both. The integration auto-detects which you're using and configures the entry shim accordingly.
Server Components
tl.create works in Server Components. The compiler transforms server-component files in the same pass as client-component files — both go through the same loader. The runtime fallback's hash is identical to the compiler's, so even if a particular path is uncompiled (e.g. third-party server module), the class names are the same.
Turbopack
Turbopack is supported via turbopack.resolveAlias. The integration sets it up automatically:
turbopack: {
resolveAlias: {
"traceless-style": path.join(__dirname, "runtime", "index.js"),
"traceless-style/dark": path.join(__dirname, "dark.js"),
"traceless-style/nextjs": path.join(__dirname, "nextjs.js"),
},
}
(On Windows, the integration converts \ → / because Turbopack rejects backslash paths.)
Caveats
- The integration does not automatically inject
<TracelessRoot />. Dark/RTL users will see a flash without it. Theinitcommand does this for you. - Webpack 4 is not supported. Next.js ≥ 14 ships webpack 5 by default.
- If you customize the
entryin your existingwebpack(config, ctx)callback, the integration's auto-CSS-injection runs before yours; chain vianextConfig.webpackcleanly.
traceless-style is published to npm. It has no required dependencies at runtime and one optional dependency (@swc/core) that the SWC-backed
tl.create works in React Server Components. The compiler transforms server-component files in the same pass as client-component files; the r
For raw webpack setups (CRA, Rspack, custom configs).