Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to import CSS modules with Typescript, React and Webpack

How to import CSS modules in Typescript with Webpack?

  1. Generate (or auto-generate) .d.ts files for CSS? And use classic Typescript import statement? With ./styles.css.d.ts:

    import * as styles from './styles.css' 
  2. Import using require Webpack function?

    let styles = require("./styles.css"); 

But for the last approach I must define the require function.

What is the best approach or best option and one that can also handle IntelliSense for the CSS file definitions and classes?

like image 262
Diego Laciar Avatar asked Dec 26 '16 22:12

Diego Laciar


People also ask

How do I use CSS modules in webpack?

To be able to use CSS in your webpack app, you need to set up a new loader. Out-of-the-box, webpack only understands Javascript and JSON. With a loader, you can translate another type of file to a format that webpack understands and can work with. There are many webpack loaders and each loader has a specific purpose.


1 Answers

A) As you are saying, there is one simplest (not best) option to use require:

const css = require('./component.css') 
  • We need to have typings for require as it's not standard feature in typescript.
  • Simplest typing for this specific require may be:

    declare function require(name: string): string; 
  • Webpack will then compile typescript and use modules properly - BUT without any IDE help and class names checks for build.

B) There is better solution to use standard import:

import * as css from './component.css' 
  • enables full class names IntelliSense
  • requires types definition for each css file, otherwise tsc compiler will fail

For proper IntelliSense, Webpack needs to generate types definition for each css file:

  1. Use webpack typings-for-css-modules-loader

    webpackConfig.module.loaders: [   { test: /\.css$/, loader: 'typings-for-css-modules?modules' }   { test: /\.scss$/, loader: 'typings-for-css-modules?modules&sass' } ]; 
  2. Loader will generate *.css.d.ts files for each of css files in your codebase

  3. Typescript compiler will understand that css import will be module with properties (class names) of type string.

Mentioned typings-for-css-loader contains a bug and because of types file generation delay, it's best to declare global *.css type in case our *.css.d.ts file is not generated yet.

That little bug scenario:

  1. Create css file component.css
  2. Include it in component import * as css from './component.css'
  3. Run webpack
  4. Typescript compiler will try to compile code (ERROR)
  5. Loader will generate Css modules typings file (component.css.d.ts), but it's late for typescript compiler to find new typings file
  6. Run webpack again will fix build error.

Easy fix is to create global definition (eg. file called typings.d.ts in your source root) for importing CSS Modules:

declare module '*.css' {   interface IClassNames {     [className: string]: string   }   const classNames: IClassNames;   export = classNames; } 

This definition will be used if there is no css file generated (eg. you have added new css file). Otherwise will be used generated specific (needs to be in same folder and named same as source file + .d.ts extension), eg. component.css.d.ts definition and IntelliSense will work perfectly.

Example of component.css.d.ts:

export const wrapper: string; export const button: string; export const link: string; 

And if you don't want to see generated css typings you may setup filter in IDE to hide all files with extension .css.d.ts in your sources.

like image 187
Jurosh Avatar answered Sep 23 '22 18:09

Jurosh