Troubleshooting
Deploy Storybook to a subdirectory or subpath
Since v3.3.3. In v3.3.2 and earlier, the default
assetPrefixwas'/'(absolute), which required manual configuration for subdirectory deployment.
The Rsbuild builder uses relative asset paths by default — the same as the official Vite (base: './') and webpack (publicPath: '') builders. Storybook can be deployed to any subdirectory (e.g., https://example.com/storybook/) without extra configuration.
Serving static assets from a CDN
Since v3.3.3. In v3.3.2 and earlier, this was not supported.
To serve Storybook's JS/CSS bundles from a separate CDN origin (e.g., https://cdn.example.com/assets/), set output.assetPrefix to the CDN URL:
The preview template correctly handles absolute URLs, so JS/CSS bundles will be loaded from the CDN while iframe.html can remain on the origin server. Note that the CDN must serve appropriate CORS headers since the bundles are loaded via ES module imports.
This is an improvement over the official webpack5 builder, which does not support CDN asset hosting due to its template always prepending ./ to import paths.
CSS url() references to static assets
In v3.3.2 and earlier, CSS
url()worked correctly when served from the root path because the defaultassetPrefixwas'/'. Since v3.3.3, the default changed to''(relative) for subdirectory support, which introduces this limitation.
When CSS files reference other assets via url() (e.g., background: url('./image.png')), the generated paths may resolve incorrectly in the production build. This happens because Rspack emits url() paths relative to the output root, but the browser resolves them relative to the CSS file's location. This is a known trade-off of using relative paths, and the official Storybook builders have the same limitation.
If your stories rely on CSS url() references, you can switch to absolute paths via output.assetPrefix:
Setting assetPrefix: '/' fixes CSS url() references when served from the root path, but breaks subdirectory deployment. Choose the option that fits your deployment scenario.
Template.toString() shows compiled code in Docs source snippet
When using the CSF 2 Template.bind({}) pattern and Template.toString() to display source code in the Docs addon, the snippet shows bundler-compiled output instead of your original source.
This is expected — Function.prototype.toString() serializes the runtime function, which has already been transformed by the bundler. This is not specific to the Rsbuild builder; the same happens with webpack and Vite.
Storybook recommends using the CSF 3 format with the automatic source snippet feature, or manually providing source code through docs source parameters. See the Storybook Docs documentation for more details.
Build errors from unexpected files
This issue mostly affects older Rspack versions. Modern Rspack handles webpackInclude correctly.
If you encounter issues where Rspack bundles files it shouldn't (like Markdown files in unexpected places), you can use rspack.IgnorePlugin to exclude them.
MSW integration and lazy compilation
When mockServiceWorker.js is found in one of the staticDirs entries — the convention used by msw-storybook-addon and any hand-rolled MSW setup — the builder automatically disables lazy compilation and logs a warning at startup.
This is necessary because MSW's Service Worker intercepts every fetch from the preview iframe, including the dev-server's lazy-compilation RPC (POST /lazy-compilation-using-). The SW's passthrough re-issues a fresh fetch(clonedRequest) that the dev-server aborts, which can leave stories stuck on a blank iframe during cold loads. The issue is rooted in how the lazy-compilation runtime talks to the dev-server via a stateful RPC channel — not a defect of the builder itself — and also affects the official @storybook/builder-webpack5 when lazy compilation is manually enabled. A related failure mode is discussed upstream in mswjs/msw#834 (SW intercepting dev-server HMR SSE).
Leaving the auto-disable in place is the safest choice. If you never explicitly set lazyCompilation, no action is required on your side.
If your project needs lazy compilation alongside MSW, set lazyCompilation explicitly in your builder options — an explicit value always takes priority over the MSW auto-disable:
When you opt back in, patch public/mockServiceWorker.js to let lazy-compilation RPC bypass MSW. Add this guard at the top of the fetch event listener, before MSW's own logic runs:
Caveats:
msw initregeneratesmockServiceWorker.jsand will overwrite the patch. Re-apply it after upgrading MSW, or automate via a postinstall script that appends the guard if it is missing.- The bypass is scoped strictly to the lazy-compilation path; normal story requests still go through MSW and your handlers behave as before.
- The substring match covers both the Rspack implementation (same-origin
POST /lazy-compilation-using-) and webpack5's (dedicated random-portGET /lazy-compilation-using-<module-path>), so the same guard also works if you ever move to the official webpack5 builder with lazy compilation enabled.
Why do sandboxes use getAbsolutePath to resolve the framework?
See Storybook's FAQ for the explanation.
How can I inspect the Rsbuild or Rspack config used by Storybook?
Rsbuild offers a CLI debug mode. Enable it when running Storybook to dump the generated configuration paths.
In development:
In production:
Check the CLI output to see where the Rsbuild and Rspack configs are written.
Can I use this builder with Rspack directly?
Yes. Rsbuild is built on Rspack, so you can feed your Rspack configuration into the Rsbuild builder. Follow the Rspack integration guide to learn how.