Skip to main content

Rspack Base Configuration

The rspack.base.config.ts is the architectural heart of the Archibald build system. It defines how source code is interpreted and how dependencies are managed across all modes and platforms.


1. Loader Rules

The base configuration defines a standardized set of loaders using SWC and Lightning CSS:

  • TypeScript/JSX: Handled by swc-loader. It supports modern features like decorators, top-level await, and the new React transform.
  • Styles: Uses a combination of sass-loader, postcss-loader, and either CssExtractRspackPlugin (for production) or style-loader (for development).
  • SVGs: Transformed into React components via @svgr/webpack or handled as raw assets depending on the import syntax.
  • Assets: Universal handling for fonts and images using Rspack's built-in asset/resource module.

2. SplitChunks (The Loadable Connection)

One of the most critical parts of the base config is the splitChunks optimization. It is designed to maximize browser caching while enabling the framework's asset discovery logic.

Cache Groups

If enabled in archibald.json, Rspack breaks the application into strategic chunks:

  • framework: Contains core libraries like react, react-dom, redux, and @archibald core packages. These rarely change and should be cached aggressively.
  • vendor: Contains all other third-party dependencies from node_modules.
  • default: The remaining application code and shared feature chunks (Islands), enabling the loadable.json manifest to map them to specific requests.

3. Resolvers & Aliases

The base config manages the complex resolution logic required for an isomorphic monorepo:

  • Shadowing Aliases: Dynamically injected based on the active Tenant and Platform. This ensures that when you import from shared/constants, the resolver picks the correct shadowed file (e.g., src/web/tenant/mytenant/constants if it exists).
  • Node Polyfills: Injected for client-side builds to support packages that expect a Node.js environment.

4. Foundational Plugins

The base configuration always includes:

  • DefinePlugin: Injects environment variables and flags (like process.env.APP_CODE) into the source code.
  • ReactLoadablePlugin: The "Recorder" that observes the chunk splitting and produces the loadable.json manifest needed for SSR.
  • TsCheckerRspackPlugin: Runs TypeScript type checking in a separate process to avoid slowing down the main compilation.

During serve it additionally installs:

  • Cache guard (archibald:rspack-cache-guard): Makes a corrupted experiments.cache store heal itself. When rspack's pack store becomes inconsistent it does not fall back to a cold build — it panics inside its Rust storage crate and aborts the process, leaving the broken store on disk so every later start dies the same way. Neither the panic message nor the abort is observable from Node (the message is written to the file descriptor from Rust; no exit handler runs after an abort), so the guard works from the absence of a signal instead: it writes a marker while a compilation is in flight and removes it shortly after the compile finishes. A marker still present at the next start means the last compile died, and the store is discarded before it can be restored. An ordinary compile error, or quitting the dev server between compiles, leaves no marker and keeps the cache. arc build additionally retries once by itself when a build worker is killed mid-compile.
  • Shadow watcher (archibald:theming-shadow-watch): Makes an override created or deleted while the dev server runs take effect. Shadowing is decided from the file system, so neither change touches any file the compiler was watching — and the Rust shadowing backend's override map is built once, when this config is constructed, because its SWC plugin runs in a WASI sandbox that cannot read the project tree. The plugin registers the source root as a contextDependency, re-derives the chain when a shadowable file appears or vanishes, corrects stale requests in normalModuleFactory.beforeResolve, re-keys the Babel cache, and adds the source tree to compiler.modifiedFiles for that one pass so every importer re-resolves. See File Shadowing for the user-facing behaviour.