There's room for improvement still. Currently, the production build is using long-dev class names. e.g. `DirectoryContent-module__Box_3__gl6dE` could be compiled to a shorter hash like `gl6DE3a2`.

If you use Vite:

  css: {
    modules: {
      generateScopedName: mode === 'production'
        ? '[hash:base64:8]'
        : '[name]__[local]___[hash:base64:5]',
      }
    }

The improvement would be shipping human-readable structure to allow easier user overrides, not that hash abomination

Those class names surely gzip better than hashes over the wire?

Here's a comparison using `brotli --best` on my app.

   53K _long.css
   38K _short.css

   11K _long.css.br
  8.9K _short.css.br
Both, dev and prod, have hashes because that's part of what CSS Modules uses to avoid collisions.

Besides download size, smaller names improve parsing speed too.

Personally I don't think this reduction in size is big enough compared to making all css names unreadable and thus very difficult to debug.

It also makes it much more difficult to create personal browser extensions as all css names are now unreadable.

Use a source map, lots of tools do that for the Js and CSS build process.

You could also drop the hash part and gain most of that improvement. Or module and hash and do better on compression (because the hash is high-entropy).

Rudimentary experiment on https://github.githubassets.com/assets/te.1288ac5c9584fbf2.m... on replacing /(?<module>[A-Za-z0-9_-]+)__(?<local>[A-Za-z0-9_-]+)__(?<hash>[A-Za-z0-9_]{5})\b/:

${module}__${local}__${hash} (original): 72967 raw, 10993 br.

${module}__${local}: 68459 raw, 8867 br.

${hash}: 48754 raw, 8189 br.

${local}: 52610 raw, 7927 br. (Now in practice a few of these are likely to need disambiguation, so it’s probably a tad smaller than realistic.)

Frankly I think ${local} is the right target, with global disambiguation where necessary. For typical systems, I consider the hash approach to be foolish: its value is when interacting with unknown other styles, but when you’re compiling everything you should know everything, so you can disambiguate more selectively and succinctly/compressibly, as JS build tools like Rollup do (in flattening modules with colliding names, you’ll get Foo, Foo$1, Foo$2, &c.).

> ${local} is the right target, with global disambiguation where necessary.

How?

---

Another approach is using base52 sequential names, such as `aa, ab, …`. I tried that a few years ago in Webpack, I don't remember but there was an issue, IIRC they weren't deterministic.

Compile everything together and you know what names are used. I can’t comment on whether it’s easy or even possible with the specific toolchain in question, but the concept is very straightforward.

Try zstandard instead of Brotli - a clearly superior format, IMO. Definitely better than gzip.

`zstd --ultra`

    53K _long.css
    11K _long.css.br
    14K _long.css.zst

    38K _short.css
   8.9K _short.css.br
    11K _short.css.zst

This.

The only thing hashing classes achieves is making it difficult for users to use ad blockers and/or custom CSS. I understand why e.g. Meta does it on their sites, but for GitHub it makes no sense.

Would you need a source map then for prod debugging?

Perhaps we should never ever use hashed class names?