Skip to main content
COSMOS RSC uses webpack to bundle your application for both client and server environments. This guide explains the webpack configuration and how the build process works.

Overview

The framework uses a single webpack configuration to build the client bundle. The server code runs directly in Node.js without bundling, using Babel for JSX transformation.

Default configuration

The webpack configuration is located at core/build/webpack.config.js:
const path = require('path');
const ReactServerWebpackPlugin = require('react-server-dom-webpack/plugin');
const { reactCompilerLoader } = require('react-compiler-webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const tailwindcss = require('@tailwindcss/postcss');
const isProduction = process.env.NODE_ENV === 'production';

module.exports = {
  mode: isProduction ? 'production' : 'development',
  entry: [
    path.resolve(__dirname, '../client/index.js'),
    path.resolve(__dirname, '../../app/globals.css'),
  ],
  output: {
    path: path.resolve(__dirname, '../../.cosmos-rsc'),
    filename: 'client.js',
  },
  devtool: isProduction ? false : 'source-map',
  // ... module rules and plugins
};

Key configuration sections

Entry points

The webpack build has two entry points:
  • core/client/index.js - The main client-side JavaScript
  • app/globals.css - Global styles for your application

Output directory

All build artifacts are written to the .cosmos-rsc directory:
  • client.js - The bundled client code
  • style.css - Extracted CSS styles
  • react-client-manifest.json - Client component references
  • react-ssr-manifest.json - SSR module mapping

Module loaders

JavaScript transformation

JavaScript files go through two loaders:
{
  test: /\.js$/,
  exclude: /node_modules/,
  use: [
    {
      loader: 'babel-loader',
      options: {
        presets: [
          [
            '@babel/preset-react',
            {
              runtime: 'automatic',
            },
          ],
        ],
      },
    },
    {
      loader: reactCompilerLoader,
    },
  ],
}
  1. babel-loader: Transforms JSX to JavaScript using the automatic runtime
  2. reactCompilerLoader: Applies React Compiler optimizations

CSS processing

CSS files are processed through a chain of loaders:
{
  test: /\.css$/i,
  use: [
    MiniCssExtractPlugin.loader,
    'css-loader',
    {
      loader: 'postcss-loader',
      options: {
        postcssOptions: {
          plugins: [tailwindcss],
        },
      },
    },
  ],
}
  1. postcss-loader: Processes Tailwind CSS directives
  2. css-loader: Resolves CSS imports
  3. MiniCssExtractPlugin.loader: Extracts CSS to a separate file

Webpack plugins

ReactServerWebpackPlugin

The most important plugin for RSC functionality:
new ReactServerWebpackPlugin({
  isServer: false,
  clientReferences: [
    {
      directory: './app',
      recursive: true,
      include: /\.js$/,
    },
    {
      directory: './core/client',
      recursive: true,
      include: /\.js$/,
    },
  ],
})
This plugin:
  • Generates the client and SSR manifests
  • Maps client component references to their bundled modules
  • Enables the server to send client component references in the RSC payload

MiniCssExtractPlugin

Extracts all CSS into a single style.css file:
new MiniCssExtractPlugin({
  filename: 'style.css',
})

Build process

The build script at core/build/index.js orchestrates the webpack build:
const fs = require('fs');
const webpack = require('webpack');
const config = require('./webpack.config');
const { BUILD_DIR } = require('../server/lib/constants');

// Clean the build directory
fs.rmSync(BUILD_DIR, {
  recursive: true,
  force: true,
});

// Run webpack
const compiler = webpack(config);
compiler.run((err, stats) => {
  // Error handling and reporting
});
The build process:
  1. Cleans the .cosmos-rsc directory
  2. Runs webpack with the configuration
  3. Reports errors or success with timing information

Development vs production

The configuration adapts based on NODE_ENV: Development mode:
  • Source maps enabled (devtool: 'source-map')
  • Faster builds with less optimization
  • Verbose error messages
Production mode:
  • No source maps (devtool: false)
  • Minification and optimization enabled
  • Smaller bundle sizes

Server-side code

Server components and server actions are NOT bundled by webpack. They run directly in Node.js with Babel transformation.
The server uses Babel’s register hook for runtime JSX transformation:
require('@babel/register')({
  ignore: [/[\/](.cosmos-rsc|node_modules)[\/]/],
  presets: [['@babel/preset-react', { runtime: 'automatic' }]],
  plugins: ['@babel/plugin-transform-modules-commonjs'],
});
This is configured in core/server/index.js and applies to all server code.

Customizing the configuration

To customize the webpack configuration:
  1. Locate core/build/webpack.config.js in your project
  2. Modify the configuration object
  3. Add new loaders, plugins, or change existing ones
  4. Run the build to test your changes

Example: Adding TypeScript support

module.exports = {
  // ... existing config
  resolve: {
    extensions: ['.js', '.jsx', '.ts', '.tsx'],
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx|ts|tsx)$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: [
                '@babel/preset-typescript',
                ['@babel/preset-react', { runtime: 'automatic' }],
              ],
            },
          },
          { loader: reactCompilerLoader },
        ],
      },
      // ... CSS rule
    ],
  },
};

Example: Adding asset handling

module.exports = {
  // ... existing config
  module: {
    rules: [
      // ... existing rules
      {
        test: /\.(png|jpg|jpeg|gif|svg)$/i,
        type: 'asset/resource',
        generator: {
          filename: 'assets/[hash][ext][query]',
        },
      },
    ],
  },
};

Manifest files

Webpack generates two critical manifest files:

react-client-manifest.json

Maps client component module IDs to their chunk information. Used by the server to reference client components in the RSC payload.

react-ssr-manifest.json

Maps module IDs to their file paths for server-side rendering. Used by the Fizz worker to resolve client components during SSR. These manifests enable the coordination between server rendering and client hydration.

Performance optimization

Code splitting

COSMOS RSC currently uses a single client bundle. Dynamic imports and code splitting are not yet configured.
Future versions may support:
  • Route-based code splitting
  • Dynamic imports for large components
  • Vendor bundle separation

Caching

For production deployments, consider:
  • Adding content hashes to filenames: filename: '[name].[contenthash].js'
  • Configuring cache headers for static assets
  • Using webpack’s caching options for faster rebuilds

Build docs developers (and LLMs) love