Skip to content

Unused CSS included in SSR build when using build.ssrEmitAssets with Vue 3 CSS modules #20917

@alexmnv

Description

@alexmnv

Describe the bug

When using Vite with Vue 3 CSS modules and the build.ssrEmitAssets option enabled, unused component styles are incorrectly included in the server build output (dist/server/assets/static/). This occurs when importing from an index file that also re-exports components with CSS modules.

The styles are only incorrectly included in the server build directory, not in the client build directory.

Reproduction

https://github.com/alexmnv/vite-ssr-css-issue-demo/

Steps to reproduce

  1. Initialize ssr-vue template
npm create vite-extra@latest demo-app -- --template ssr-vue
cd demo-app
npm install
  1. Enable build.ssrEmitAssets in vite.config.js

  2. Create the following structure:

    src/
    ├─ feature/
    │  ├─ Feature.vue
    │  ├─ FeatureInner.vue
    │  └─ index.js
    └─ App.vue
    
  3. In feature/index.js, re-export a component and a constant:

    // src/feature/index.js
    export { default as Feature } from './Feature.vue';
    export const foo = 'foo';
  4. In Feature.vue, import another component and use CSS modules:

    <!-- src/feature/Feature.vue -->
    <template>
     <div :class="$style.feature">
        <FeatureInner />
     </div>
    </template>
    
    <script setup>
    import FeatureInner from './FeatureInner.vue';
    </script>
    
    <style module>
    .feature {
      color: red;
    }
    </style>
  5. In FeatureInner.vue, also use CSS modules:

    <!-- src/feature/FeatureInner.vue -->
    <template>
      <div :class="$style.featureInner">Inner</div>
    </template>
    
    <style module>
    .featureInner {
      color: blue;
    }
    </style>
  6. In another component (e.g. App.vue), import only the constant, not the component:

    <script setup>
    import { foo } from './feature';
    </script>
    
    <template>{{ foo }}</template>
  7. Build:

    npm run build

Expected Behavior

Only the styles of actually used components (in this case, App.vue) should be emitted.
No CSS related to Feature.vue or FeatureInner.vue should be present.

Actual behavior

  • ✅ Client build (dist/client/assets/static/): Correctly excludes unused component styles
  • ❌ Server build (dist/server/assets/static/): Incorrectly includes styles from FeatureInner component

The styles are included in the server build even though the components are never imported or rendered.
Note that only the styles from FeatureInner are included, while the Feature component’s styles are not.

Additional notes

  • This issue only occurs when using Vue 3 CSS modules (<style module>). Regular <style> or <style scoped> do not trigger this bug.
  • Steps 2 - 7 are implemented in this commit of reproduction demo.

System Info

System:
    OS: Linux 6.8 Ubuntu 24.04.3 LTS 24.04.3 LTS (Noble Numbat)
    CPU: (16) x64 AMD Ryzen 7 5800U with Radeon Graphics
    Memory: 4.44 GB / 30.66 GB
    Container: Yes
    Shell: 5.2.21 - /bin/bash
  Binaries:
    Node: 23.9.0 - /home/pumbo/.nvm/versions/node/v23.9.0/bin/node
    npm: 10.9.2 - /home/pumbo/.nvm/versions/node/v23.9.0/bin/npm
  Browsers:
    Chrome: 140.0.7339.127
    Firefox: 143.0.4
    Firefox Developer Edition: 143.0.4

Used Package Manager

npm

Logs

No response

Validations

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions