webpack-typings-for-css

Webpack loader that generates TypeScript typings for CSS modules

Usage no npm install needed!

<script type="module">
  import webpackTypingsForCss from 'https://cdn.skypack.dev/webpack-typings-for-css';
</script>

README

Webpack Typings for CSS loader

NPM License Quality Code Climate Downloads Build

Webpack loader that generates TypeScript typings for CSS modules

Installation

npm install webpack-typings-for-css --save-dev

webpack.config.js

module.exports = {
    module: {
        rules: [{
            test: /\.css$/,
            use: [{
                loader: 'style-loader'
            }, {
                loader: 'webpack-typings-for-css'
            }, {
                loader: 'css-loader',
                options: {
                    localsConvention: 'camelCaseOnly',
                    modules: {
                        localIdentName: '[name]__[local]__[hash:base64]'
                    }
                }
            }]
        }]
    }
};

Example

Let's say we are building a simple React button component. And we have this file: ./src/button/style.scss in our project with the following content:

.button {
    color: black;
    background: white;
    font-size: 12px;
    padding: 10px;

    &--small {
        padding: 5px;
        font-size: 10px;
    }

    &--large {
        padding: 20px;
        font-size: 14px;
    }
}

When we add the webpack-typings-for-css loader, this will generate a TypeScript definition file ./src/button/style.scss.d.ts with the following content:

declare const styles = {
    button: 'styles__button__2wmORyJZRJFrl_Mc46Dxnh',
    buttonSmall: 'styles__button--small__1dezcn7Xl7U8em93APXPIU',
    buttonLarge: 'styles__button--large__2GA-bPwea6oWSnVWqjy_ux',
} as const;

export type ClassName = (
    'styles__button__2wmORyJZRJFrl_Mc46Dxnh' |
    'styles__button--small__1dezcn7Xl7U8em93APXPIU' |
    'styles__button--large__2GA-bPwea6oWSnVWqjy_ux'
);

export default styles;

In your Typescript file you will now be able to import this file and get type hints with the available classNames. The values for these properties are the final classNames that are generated by the css-loader. In our example they are hashed:

import styles from './styles.scss';

console.log(styles.button); // styles__button__wzc-BjG34gg0YTmmp71Mh
console.log(styles.buttonSmall); // styles__button--small__Jl0thjpdKMgQgK4SczMV_
console.log(styles.buttonLarge); // styles__button--large__2vSRkXkjXTxZOTMAbhDH_n

In your (React) button component you can now use the same import and use these readable type checked classNames to style your components!

import React from 'react';

import styles from './styles.scss';

export const Button = () => (
    <button className={styles.button}>Hello World!</button>
);

Known issues

As the loader generates typing files, it is wise to tell webpack to ignore them. The fix is luckily very simple. Webpack ships with a "WatchIgnorePlugin" out of the box. Simply add this to your webpack plugins:

plugins: [
    new webpack.WatchIgnorePlugin([
        /css\.d\.ts$/
    ]),
    ...
]

You might see project warnings when you have not yet build the project. This happens because Typescript cannot import SCSS, LESS or CSS files (since they are not official modules). In order to fix this you can add a type definition to your project. You can find the common examples in the typings folder of this project.

Let's say your project uses SCSS files for styling then add the following file to your project:

./typings/scss.d.ts

declare module '*.scss' {

    declare const styles: {
        readonly [key: string]: string;
    };

    export type ClassName = string;

    export default styles;
}

tsconfig.json

{
    ...
    "files": [
        "./typings/scss.d.ts"
    ],
    ...
}