Skip to content

CSS chunk files not emitted for lazy-loaded routes with MiniCssExtractPlugin in 5.108.0 #21306

Description

@animeshpriyadarshi1008

Have you used AI?

No

Bug Description

After upgrading to webpack 5.108.0, CSS chunk files for lazily-loaded routes are no longer emitted as separate files during production builds. Only main.css (and occasionally one chunk CSS) is generated in the output directory.

The JS chunks and asset-manifest.json still reference companion CSS chunk files, but those files do not exist on disk. This causes broken styles at runtime when users navigate to lazy-loaded routes — the browser requests a CSS chunk that doesn't exist.

The build completes without any errors or warnings related to CSS extraction. This is a silent regression.

Link to Minimal Reproduction and step to reproduce

Project structure:

project/
├── webpack.config.js
├── package.json
└── src/
    ├── App.jsx
    ├── index.js
    └── routes/
        ├── Home/
        │   ├── index.jsx
        │   └── styles.scss
        ├── Dashboard/
        │   ├── index.jsx
        │   └── styles.scss
        └── Settings/
            ├── index.jsx
            └── styles.scss

package.json:

{
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.16.0",
    "react-scripts": "5.0.1"
  },
  "devDependencies": {
    "sass": "^1.69.2"
  },
  "scripts": {
    "build": "GENERATE_SOURCEMAP=false react-scripts build && node cacheBuster.js"
  }
}

webpack optimization (applied via react-scripts internal config):

react-scripts 5.0.1 internally uses:

  • mini-css-extract-plugin for CSS extraction
  • optimization.splitChunks for code splitting
  • chunkIds: 'deterministic' was set via configuration override

src/App.jsx:

import React, { lazy, Suspense } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';

const Home = lazy(() => import('./routes/Home'));
const Dashboard = lazy(() => import('./routes/Dashboard'));
const Settings = lazy(() => import('./routes/Settings'));

export default function App() {
    return (
        <BrowserRouter>
            <Suspense fallback={<div>Loading...</div>}>
                <Routes>
                    <Route path="/" element={<Home />} />
                    <Route path="/dashboard" element={<Dashboard />} />
                    <Route path="/settings" element={<Settings />} />
                </Routes>
            </Suspense>
        </BrowserRouter>
    );
}

src/routes/Dashboard/index.jsx:

import './styles.scss';

export default function Dashboard() {
    return <div className="dashboard">Dashboard Page</div>;
}

src/routes/Dashboard/styles.scss:

.dashboard {
    background: #f0f0f0;
    padding: 20px;
    border-radius: 8px;
}

Steps to reproduce:

  1. Install dependencies with webpack@5.108.0 resolved (no lockfile pinning)
  2. Run npx craco build (or react-scripts build)
  3. Inspect build/static/css/ — only main.*.css exists
  4. Check build/asset-manifest.json — references multiple chunk CSS files that don't exist on disk
  5. Serve the app and navigate to /dashboard — styles are missing

Expected Behavior

CSS imported within lazily-loaded components should be extracted into separate chunk CSS files (e.g., 1909.a8bc7e25.chunk.css, 3394.a4a9f8d1.chunk.css, etc.), one per async JS chunk that contains CSS imports. This is the behavior on webpack 5.107.2 and all prior 5.x versions.

Expected output:

build/static/css/main.b609dbcd.css
build/static/css/135.a06a1b74.chunk.css
build/static/css/153.a8bc7e25.chunk.css
build/static/css/51.85a2f82c.chunk.css
build/static/css/519.45866358.chunk.css
build/static/css/60.807e66bf.chunk.css
build/static/css/71.3cf9508a.chunk.css
build/static/css/791.deec7020.chunk.css
build/static/css/836.d4c43bca.chunk.css
build/static/css/84.a6bc2991.chunk.css
build/static/css/900.98c6f4aa.chunk.css
build/static/css/939.04c0c65e.chunk.css
... (one CSS chunk per lazy route with CSS imports)

Actual Behavior

Only main.css and at most one chunk CSS file are emitted:

build/static/css/main.0de701e6.css
build/static/css/153.a8bc7e25.chunk.css

The asset-manifest.json still lists all expected CSS chunk files. The JS runtime still attempts to load them. But the files are not on disk.

No build errors or warnings are shown. The regression is completely silent.


Environment

System:
  OS: Linux (Alpine 3.21) / macOS darwin arm64
  Node: 16.17.0 / 18.20.8 (reproduced on both)
  npm: 8.15.0
  pnpm: 8.15.9

Packages:
  webpack: 5.108.0
  mini-css-extract-plugin: 2.7.6 (bundled via react-scripts 5.0.1)
  css-loader: 6.7.3 (bundled via react-scripts 5.0.1)
  sass-loader: 13.2.0 (bundled via react-scripts 5.0.1)
  @craco/craco: 7.1.0
  react-scripts: 5.0.1


---

Is this a regression?

None

Last Working Version

5.107.2

Additional Context

Pinning webpack to 5.107.2 via pnpm overrides restores correct behavior:

{
  "pnpm": {
    "overrides": {
      "webpack": "5.107.2"
    }
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions