Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Class shaker

Open
#9 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
35/100
Issue type
Feature
Clarity
Mostly clear
Activity status
Stale
Tech stack
css, typescript, vite

Research direction

Start by reading the plugin's Vite integration and the JavaScript and CSS output stages. Review the proposed PurgeCSS custom extractor and the suggested { shake: true } option. Done means unused CSS Module classes are removed without removing referenced classes, with the behavior verified on a Vite build.

Written by the indexing model from the issue text.

Description

question

One thing that surprised me about CSS Modules in Vite is that it doesn't automatically shake unreferenced classes.

.unused {
   font-size: 42px;
}

.used {
   font-size: 27px;
}
import { used } from './foo.module.css'

...

The .unused class will appear in the output.

I noticed that this plugin does not shake unused classes either, so I made a small postprocessor that does the job.

If this seems like a good idea, I wonder if it could be incorporated into this plugin somehow. Basically it scans through the JS files to gather possible class names (/"([A-Za-z_]{1,2})"/g) then uses PurgeCSS with a custom extractor to strip the unused classes.

I think this could be incorporated as a { shake: true } option for this plugin. Shaking would require hooking into the JS output from Vite, marking known class names as used, and then stripping the unused ones before outputting the final CSS.

import { readFileSync, writeFileSync } from 'fs'
import { ExtractorResultDetailed, PurgeCSS } from 'purgecss'

const tags = ['a', 'abbr', ...]

const purgeFromJs = (content: string): ExtractorResultDetailed => {
  const regex = /"([A-Za-z_]{1,2})"/g
  const matches: string[] = []
  let match: RegExpExecArray | null

  while ((match = regex.exec(content)) !== null) {
    matches.push(match[1])
  }

  // console.log(`Possible classes (${matches.length}): ${matches.join(', ')}`)
  return {
    attributes: {
      names: [],
      values: [],
    },
    ids: [],
    tags,
    undetermined: [],
    classes: matches,
  }
}

const purgeCSSResult = await new PurgeCSS().purge({
  content: ['dist/assets/*.js'],
  css: ['dist/assets/*.css'],
  extractors: [
    {
      extractor: purgeFromJs,
      extensions: ['js'],
    },
  ],
})

// process.exit(0)

purgeCSSResult.forEach((result) => {
  const { css, file } = result
  if (!file) return
  const bytesBefore = Buffer.byteLength(readFileSync(file, 'utf-8'), 'utf-8')
  const bytesAfter = Buffer.byteLength(css, 'utf-8')
  console.log(`Writing optimized css: ${file}`)
  writeFileSync(file, css)
  console.log(`Reduced size from ${bytesBefore} to ${bytesAfter} bytes`)
})
Dominant language
CSS
Stars
48
Forks
5
PR merge metrics
No merged PRs in 30d

Getting set up

We have not checked this project's setup files yet. Start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from simonwep/vite-plugin-optimize-css-modules

All issues in simonwep/vite-plugin-optimize-css-modules

Similar issues

More Build System issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.