Compression of css classes. Next.js. Let’s make the web Even faster
Tags: nextjs, webdev, react, frontend
Published: 2024-01-16 18:23:25

For many years, there have been debates about how best to name classes — according to BEM, by objectives, by components or however you like, but with the addition of a hash. And this is indeed an important question, which method will be comfortable in the development of a large and evolving project. But, what do these methods mean for the user, does he need these classes and how are they related to his experience?

Sometimes, when I go into the styles of projects, I involuntarily get scared of the formed length of names — module, block, element, subelement, modifier 1, modifier 2. BEM is really great and I don’t intend to deny it, but its sizes leave much to be desired.

Long classes increase the weight of the page, this in turn means an increase in the loading time of the most important for rendering the page — the document and the style file, which directly affect the FCP (_First Contentful Paint_), LCP (_Largest Contentful Paint_) metrics.

This has become one of the reasons why I have been looking at modules for a long time (_in addition to isolating styles and storing them where they are used_).

Modules allow you to name classes shorter, only for the current component, while maintaining the convenience of development. But now hashes are added to the classes, making them longer, so the advantage is not as much as one would like. Therefore, finally, to the topic of the article.

## Compression of class names
So, what are the methods to shorten classes:
- Name classes shorter (_Thanks Captain, yes_);
- Name classes fully, but only leave the hash during assembly;
- Name names according to a certain rule or algorithm.

The first way is not suitable for something bigger than a to-do list — making classes too short we either lose DX, or risk making intersections.

For the second and third methods, css-loader offers the `localIdentName` property for modules.

`localIdentName: "[path][name]__[local]--[hash:base64:5]"`

`localIdentName: "[hash:base64]"`

The most optimal compression
By choosing a rule, you can significantly reduce the size of classes, but still, significantly is not equal to maximum. The maximum reduction of class names will be reduced to characters — `.a`, `.b`, `.c`, ..., etc.

This approach is used, for example, by Google, Facebook, Instagram

To implement such a solution, we are interested in the getLocalIdent property, which allows you to pass a function for generating a name. You can also use packages such as [posthtml-minify-classnames](https://github.com/posthtml/posthtml-minify-classnames) or [mangle-css-class-webpack-plugin](https://github.com/sndyuk/mangle-css-class-webpack-plugin).

The article could have been finished at this point, if it were not for one detail. I use next.js.

## Solution
Next.js has several features that do not allow these solutions to be used. The most obvious feature is that it does not allow you to configure getLocalIdent from the outside.

That’s why I, 3 years ago, made a package — `next-classnames-minifier`. In it, I implemented a name selection algorithm and set up the embedding of `getLocalIdent` in the necessary rules in webpack. Over the following years, the package was slightly updated, but there was something in it that didn't allow me to call it completed and ready for use in commercial projects.

The main problem was the need to delete the folder of the built application and cache in ci every time, which, of course, greatly affected the convenience of development. And this is the second feature of Next — its caching system.

If a component was built, then at the next launch of the development mode or assembly — it may not be rebuilt. That is, when restarting, the algorithm started to work from scratch and generated classes with the simplest names (`.a`, `.b`, `.c`), but in a number of non-rebuildable components and styles such names were added at the last launch.

For this reason, the solution is not included in next.js

![The response from the co-author of next.js on compressing class names](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/il3kxtioqxsgdt24m3nd.png)
_The response from the co-author of next.js on compressing class names_

## Make friends with Next.js
Obviously, it was critically important to get rid of the cache clearing problem. And the solution was found. Now the package, like next.js, caches the results — generated names — and at each start restores them from the cache, analyzing them and checking their relevance.

At the same time, the assembly speed did not become longer, since the package uses the same optimized name selection algorithm, and due to caching the package works even faster _[than the basic creation of names with hash generation_].

## Efficiency
You can find articles with compression efficiency of 30%, 50% and even 70%. In reality, everything is very individual. For example, if you had a class:

```css
.postsListItemTitle {
	font-size: 24px;
}
```
From it you get:

```css
.j1 {
	font-size: 24px;
}
```

21 characters (`.j1{font-size: 24px;}`) instead of 44 (`.postsListItemTitle__h53_j{font-size: 24px;}`) - savings of 52%. This class is used in 20 cards on the page, which reduces the weight of html as well.

On average, however, one can speak of a reduction in the weight of css by 10–20%.

[next-classnames-minifier](https://github.com/vordgi/next-classnames-minifier) — let’s make the web Even faster.