Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
April 26, 2023 02:17 pm GMT

How to write type-safe CSS Modules

Written by Alain Perkaz

One of the benefits of using TypeScript is that it significantly reduces the occurrence of specific bugs, like typos; it even makes it easier to access prototype methods and perform refactoring. Bugs caught at compile time make for more uptime, happier customers, and less on-call stress for developers.

With TypeScript, it's easy to type our applications business logic and control flows, but what if we could make our CSS classes safe too? Having the correct CSS class names in place ensures that the intended styles are applied to a given component, preventing the styles from being misplaced due to typography errors.

In this article, well discuss what CSS Modules are, explore their developer experience shortcomings, and learn how to address them by using automation with TypeScript.Lets get started!

Jump ahead:

  • What are CSS Modules?
  • Adding CSS Modules to your project
  • Developer experience improvements
  • Automatic typings

What are CSS Modules?

CSS Modules provide an approach to writing modular and scoped CSS styles in modern web apps. These styles are specific to your application's particular component or module. You can write CSS Modules by using regular CSS.

At build time, with Vite or other similar tools, the CSS Modules generate unique class names for each class defined in the CSS files. The generated class names are then used in JavaScript to refer to the CSS, thereby making the CSS modular and reusable without class name conflicts or unnecessary duplications.

At the time of writing, CSS class names are no longer global, solving many of the pains that methodologies like BEM were designed to solve, but without the manual effort. However, following BEM within CSS Modules can still be beneficial depending on the use case.

Adding CSS Modules to your project

If you want to use CSS Modules in your next TypeScript app, you have several options.

Modern build tools like Vite and Snowpack support CSS Modules out of the box, but you may need to includesome minor configurations if youre using webpack.

Once the build setup is done, you can add CSS files with the module.css extension following the CSS Modules convention:

// button.module.css.green {    background-color: 'green';}.blue {    background-color: 'blue';}.red {    background-color: 'red';}

To apply those styles and leverage the benefits mentioned above, we should import the CSS Module from a TypeScript file and bind the HTML. Keep in mind that the example below is written in React, but the syntax is very similar to other UI libraries:

// Component.tsximport styles from './button.module.css'const Component = () => (    <>        <button className={styles.green}>I am green!</button>        <button className={styles.blue}>I am blue!</button>        <button className={styles.red}>I am red!</button>    </>)

If you run the code above locally, youll notice that the returned styles are not typed restrictively. Instead, they are typed as any. Additionally, the TypeScript compiler wont notify you if the class name doesnt exist. Let's discuss what that means for the developer in detail.

Developer experience improvements

CSS Modules are a great tool, but since class names are generated at runtime and change between builds, its hard to use them in a type-safe way.

You could manually create types for each CSS Module using TypeScript definition files, but updating them is tedious. Let's suppose that a class name is added or removed from the CSS Module. In that case, the types must be manually updated, otherwise, the type safety won't work as expected.

For the example above, the typings would be as follows:

// button.module.css.d.ts -  the CSS Module typesdeclare const styles: {  readonly green: string;  readonly blue: string;  readonly red: string;};export default styles;

These types will work well until we modify the related CSS Module. Once we modify it, well have to update the typings. If we forget to update the typings manually, some nasty UI bugs might appear:

// button.module.css.green {    background-color: 'green';}.blue {     background-color: 'blue';}/*  the `red` classname is removed */

We forgot to modify the related typings file:

// button.module.css.d.tsdeclare const styles: {  readonly green: string;  readonly blue: string;  readonly red: string; //  we forgot to update the types! };export default styles;// Component.tsximport styles from './button.module.css'const Component = () => (    <>        <button className={styles.green}>I am green!</button>        <button className={styles.blue}>I am blue!</button>        {/*  `red` does not exist, but since we forgot to update the types, the compiler wont fail! */}        <button className={styles.red}>I am red!</button>    </>)

The situation shown in this example might not seem relevant, but as the codebase and number of contributors grow, this repetitive and error-prone process will hinder trust in the type-system. Referencing non-existent or mistyped CSS classes won't style the HTML as expected, which can quickly snowball into developers losing trust in the tooling. Let's learn how to automate it!

Automatic typings

In this case, the automation solution is straightforward. Well generate the types automatically instead of manually, and well provide a script to verify that the generated types are up-to-date to avoid incorrect CSS Module typings leaking into the compilation step.

There are multiple ways to achieve this. For example, we could build a CSS to TypeScript definition extractor. However, to avoid re-inventing the wheel, well leverage the open source package typed-css-modules. Lets get to it!

Install the package in your project with npm i typed-css-modules, then add the type-generation to your main development script in the package.json scripts:

"watch": "vite & tcm --watch .",

Add the check for up-to-date types. If the generated types are not correct in the package.json scripts, it will fail:

"check:up-to-date-types": "tcm --listDifferent .",

With these two scripts, its now possible to automatically keep the CSS Module type definitions in sync and check if the types are kept up to date.

Depending on the project, you may prefer to run these scripts locally or in a server, perhaps as a part of your CI pipeline. To round out the example, well describe how to run them as a Git Hook using husky:

Install and set up the Git Hook runner with npx husky-init && npm install. To set up a pre-commit Hook to run the CSS Module type checking before every commit, modify the .husky/pre-commit file to the following:

#!/usr/bin/env sh. "$(dirname -- "$0")/_/husky.sh"npm run check:up-to-date-types

Before every commit, the hook will run and verify that the types are up to date. Handy!

Conclusion

Working within the TypeScript ecosystem has great potential, but, when leaning too much on manual processes, it's easy to blow trust in the type-system or generate unnecessary friction.

CSS Modules are great, and with a little bit of extra configuration, its easy to add type safety to the generated classes. You should automate the boring stuff so that your team can focus on building a great products instead. I hope you enjoyed this article, and be sure to leave a comment below if you have questions. Happy coding!

Is your frontend hogging your users' CPU?

As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If youre interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.

LogRocket Dashboard Free Trial Banner

LogRocket is like a DVR for web apps, recording everything that happens in your web app or site. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.

Modernize how you debug web apps Start monitoring for free.


Original Link: https://dev.to/logrocket/how-to-write-type-safe-css-modules-56e0

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To