Drop-in replacement for css-loader to generate typings for your CSS-Modules on the fly in webpack
npm install typings-for-css-modules-loaderWebpack loader that works as a css-loader drop-in replacement to generate TypeScript typings for CSS modules on the fly
Install via npm npm install --save-dev typings-for-css-modules-loader
Just like any other loader you can specify options e.g. as query-params
-) that are not valid characters for a typescript variable the default behaviour for this loader is to export an interface as the default export that contains the classnames as properties.ts
export interface IExampleCss {
'foo': string;
'bar-baz': string;
}
declare const styles: IExampleCss;export default styles;
`A cleaner way is to expose all classes as named exports, this can be done if you enable the
namedExport-option.
e.g.
`js
{ test: /\.css$/, loader: 'typings-for-css-modules?modules&namedExport' }
`As mentioned above, this requires classnames to only contain valid typescript characters, thus filtering out all classnames that do not match /^\w+$/i. (feel free to improve that regexp)
In order to make sure that even classnames with non-legal characters are used it is highly recommended to use the
camelCase-option as well, that - once passed to the css-loader - makes sure all classnames are transformed to valid variables.
with:
`js
{ test: /\.css$/, loader: 'typings-for-css-modules?modules&namedExport&camelCase' }
`
using the following css:
`css
.foo {
color: white;
}.bar-baz {
color: green;
}
`will generate the following typings file:
`ts
export const foo: string;
export const barBaz: string;
`css-loader exports mappings to exports.locals which is incompatible with the namedExport-option unless paired with extract-text-webpack-plugin or style-loader. They move the exported properties from exports.locals to exports making them required for namedExport to work, and namedExport required for them to work. Always combine usage of extract-text-webpack-plugin or style-loader with the namedExport-option.$3
To silence the loader because you get annoyed by its warnings or for other reasons, you can simply pass the "silent" query to the loader and it will shut up.
e.g.:`js
{ test: /\.css$/, loader: 'typings-for-css-modules?silent' }
`$3
To add a "banner" prefix to each generated *.d.ts file, you can pass a string to this option as shown below. The prefix is quite literally prefixed into the generated file, so please ensure it conforms to the type definition syntax.`js
{ test: /\.css$/, loader: 'typings-for-css-modules?banner="// This file is automatically generated by typings-for-css-modules.\n// Please do not change this file!"' }
`Usage
Keep your
webpack.config as is just instead of using css-loader use typings-for-css-modules-loader
its important you keep all the params that you used for the css-loader before, as they will be passed along in the processbefore:
`js
webpackConfig.module.loaders: [
{ test: /\.css$/, loader: 'css?modules' }
{ test: /\.scss$/, loader: 'css?modules&sass' }
];
`after:
`js
webpackConfig.module.loaders: [
{ test: /\.css$/, loader: 'typings-for-css-modules?modules' }
{ test: /\.scss$/, loader: 'typings-for-css-modules?modules&sass' }
];
`Example
Imagine you have a file
~/my-project/src/component/MyComponent/myComponent.scss in your project with the following content:
`css
.some-class {
// some styles
&.someOtherClass {
// some other styles
}
&-sayWhat {
// more styles
}
}
`Adding the
typings-for-css-modules-loader will generate a file ~/my-project/src/component/MyComponent/myComponent.scss.d.ts that has the following content:
`ts
export interface IMyComponentScss {
'some-class': string;
'someOtherClass': string;
'some-class-sayWhat': string;
}
declare const styles: IMyComponentScss;export default styles;
`$3
Using the namedExport as well as the camelCase options the generated file will look as follow:
`ts
export const someClass: string;
export const someOtherClass: string;
export const someClassSayWhat: string;
`$3
!typed-css-modulesIf you encounter the following errors:
`
error TS1192: Module '"xxxxx/xxxx/src/style.sass"' has no default export.
`
maybe you should export the styles as following:
`
import * as styles from './style.sass';
`Support
As the loader just acts as an intermediary it can handle all kind of css preprocessors (
sass, scss, stylus, less, ...).
The only requirement is that those preprocessors have proper webpack loaders defined - meaning they can already be loaded by webpack anyways.Requirements
The loader uses
css-loader(https://github.com/webpack/css-loader) under the hood. Thus it is a peer-dependency and the expected loader to create CSS Modules.Known issues
$3
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$/
]),
...
]
`
where css is the file extension of your style files. If you use sass you need to put sass here instead. If you use less, stylus` or any other style language use their file ending.As the webpack process is independent from your typescript "runtime" it may take a while for typescript to pick up the typings.
Any hints on how this could be fixed deterministically are welcome!