I want to use the css-loader with the 'modules' option of webpack in a React application written in Typescript. This example was my starting point (they are using Babel, webpack and React).

webpack config

var webpack=require('webpack');
var path=require('path');
var ExtractTextPlugin=require("extract-text-webpack-plugin");

module.exports={
    entry: ['./src/main.tsx'],
    output: {
        path: path.resolve(__dirname, "target"),
        publicPath: "/assets/",
        filename: 'bundle.js'
    },
    debug: true,
    devtool: 'eval-source-map',
    plugins: [
        new webpack.optimize.DedupePlugin(),
        new webpack.optimize.UglifyJsPlugin({minimize: true})
    ],
    resolve: {
        extensions: ['', '.jsx', '.ts', '.js', '.tsx', '.css', '.less']
    },
    module: {
        loaders: [
            {
                test: /\.ts$/,
                loader: 'ts-loader'
            },
            {
                test: /\.tsx$/,
                loader: 'react-hot!ts-loader'
            }, {
                test: /\.jsx$/,
                exclude: /(node_modules|bower_components)/,
                loader: "react-hot!babel-loader"
            },
            {
                test: /\.js$/,
                exclude: /(node_modules|bower_components)/,
                loader: "babel-loader"
            }, {
                test: /\.css/,
                exclude: /(node_modules|bower_components)/,
                loader: ExtractTextPlugin.extract('style-loader', 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss-loader')
            }
        ]
    },
    plugins: [
        new ExtractTextPlugin("styles.css", {allChunks: true})
    ],
    postcss: function() {
        return [require("postcss-cssnext")()]
    }
}

This is a React component I want to style with an accompanying CSS file:

import React = require('react');
import styles = require('../../../css/tree.css')

class Tree extends React.Component<{}, TreeState> {
...

    render() {
        var components = this.state.components
        return (
            <div>
                <h3 className={styles.h3} >Components</h3>
                <div id="tree" className="list-group">
                    ...
                </div>
            </div>
        )
    }
}

    export = Tree

tree.css

.h3{
    color: red;
}

No matter what I'm doing (tried changing the import syntax, tried declaring the 'require' for ts-loader, described here, I always get:

Uncaught Error: Cannot find module "../../../css/tree.css"

at runtime and

error TS2307: Cannot find module '../../../css/tree.css'.

by the TS compiler. Whats happening? Seems to me that css-loader is not even emitting ICSS? Or is it ts-loader behaving wrong?

share|improve this question
    
import someName = require('/some/path') is two different kinds of invalid ;-) - are you using import or require? – Sean Vieira Jan 26 at 13:19
    
What do you mean? Thats valid Typescript syntax. @SeanVieira – Shady Jan 26 at 13:37
1  
Yea, TypeScript adopted sort of their own module syntax while ES6 modules were still being developed. It's a hybrid between CJS and ES6 where you use import (like ES6) but also require (like CJS). TypeScript also (now) supports full ES6 syntax though as well. – James Brantly Jan 26 at 13:45
up vote 3 down vote accepted

import has special meaning to TypeScript. It means that TypeScript will attempt to load and understand the thing being imported. The right way is to define require like you mentioned but then var instead of import:

var styles = require('../../../css/tree.css')`
share|improve this answer
    
Do I still need to define 'require' in a d.ts? Do I have to target ES6 in my tsconfig? I get the same error @James Brantly – Shady Jan 26 at 13:56
    
You need to define require in a d.ts, yes, otherwise TypeScript will complain that there is no require function. The target doesn't matter, should work the same using any target. Do you still see specifically "TS2307"? If not, then it's no longer a TypeScript error and it's webpack saying that it can't find the file (due to a bad path). – James Brantly Jan 26 at 14:07
    
Yes you are right, the TS2307 is gone. The runtime error comes from webpack. How do I need to understand the path? Is it relative to the webpack.config.js? – Shady Jan 26 at 14:08
    
No, it's relative to the file that's doing the requiring. – James Brantly Jan 26 at 14:08
    
Right... webpack just cant find the file. I tried pulling it into the same directory as the .tsx file. No luck... Do you have a working example of Typescript+rect+modules at hand? – Shady Jan 26 at 14:11
  1. Declare 'require' as per ts-loader documentation.
  2. Use 'require' as generic with < any > type: require< any >("../../../css/tree.css").

*.d.ts file

declare var require: {
   <T>(path: string): T;
   (paths: string[], callback: (...modules: any[]) => void): void;
   ensure: (paths: string[], callback: (require: <T>(path: string) => T) => void) => void;
}; 

*.tsx file with component

const styles = require<any>("../../../css/tree.css");
...
<h3 className={styles.h3}>Components</h3>

I know it was already answered, but I was struggling with it for a while before I realized I need to use generic type specification, without that I wasn't able to access content of CSS file. (I was getting error: Property 'h3' does not exists on type '{}'.)

share|improve this answer
    
Yeah or you can just leave away the generic <T> in the declaration of 'require': declare var require:{(path: string): T} – Shady Mar 22 at 9:30

I had similar problem. For me, works import:

import '../../../css/tree.css';

Webpack change this like any other normal imports. It change it to

__webpack_require__(id)

One drawback is that you lost control on style variable.

share|improve this answer
1  
But I need the variable 'styles' for setting the className in the React component like: <div className={styles.style}/> Can you explain further what you mean? – Shady Jan 26 at 13:36
    
All styles are available as normal css. Then you could use it in your h3 component: <h3 className="h3" >Components</h3> – Krzysztof Sztompka Jan 26 at 13:41
    
I see what you mean, but my goal is to use CSS modules where every CSS file is scoped locally (one css file per react component). Thats why I need to assign the className programmatically – Shady Jan 26 at 14:01
    
I see, I didn't find any better solution only this workaround. I will follow this question, maybe you will have a luck. – Krzysztof Sztompka Jan 26 at 14:21

You can use https://github.com/Quramy/typed-css-modules, which creates .d.ts files from CSS Modules .css files. Please see also https://github.com/css-modules/css-modules/issues/61#issuecomment-220684795

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.