Unable to import CSS / SCSS modules. TypeScript says: "Cannot find module"

I am trying to import a theme from a CSS module, but TypeScript gives me the error "Cannot find the module" and the theme does not apply at runtime. I think something is wrong with my Webpack configuration, but I'm not sure where the problem is.

I use the following tools:

"typescript": "^2.0.3" "webpack": "2.1.0-beta.25" "webpack-dev-server": "^2.1.0-beta.9" "react": "^15.4.0-rc.4" "react-toolbox": "^1.2.3" "node-sass": "^3.10.1" "style-loader": "^0.13.1" "css-loader": "^0.25.0" "sass-loader": "^4.0.2" "sass-lint": "^1.9.1" "sasslint-webpack-plugin": "^1.0.4" 

Here is my webpack.config.js

 var path = require('path'); var webpack = require('webpack'); var sassLintPlugin = require('sasslint-webpack-plugin'); module.exports = { entry: [ 'webpack-dev-server/client?http://localhost:8080', 'webpack/hot/dev-server', './src/index.tsx', ], output: { path: path.resolve(__dirname, 'dist'), publicPath: 'http://localhost:8080/', filename: 'dist/bundle.js', }, devtool: 'source-map', resolve: { extensions: ['.webpack.js', '.web.js', '.ts', '.tsx', '.js'], }, module: { rules: [{ test: /\.js$/, loader: 'source-map-loader', exclude: /node_modules/, enforce: 'pre', }, { test: /\.tsx?$/, loader: 'tslint-loader', exclude: /node_modules/, enforce: 'pre', }, { test: /\.tsx?$/, loaders: [ 'react-hot-loader/webpack', 'awesome-typescript-loader', ], exclude: /node_modules/, }, { test: /\.scss$/, loaders: ['style', 'css', 'sass'] }, { test: /\.css$/, loaders: ['style', 'css'] }], }, externals: { 'react': 'React', 'react-dom': 'ReactDOM' }, plugins: [ new sassLintPlugin({ glob: 'src/**/*.s?(a|c)ss', ignoreFiles: ['src/normalize.scss'], failOnWarning: false, // Do it. }), new webpack.HotModuleReplacementPlugin(), ], devServer: { contentBase: './' }, }; 

and my App.tsx , where I am trying to import:

 import * as React from 'react'; import { AppBar } from 'react-toolbox'; import appBarTheme from 'react-toolbox/components/app_bar/theme.scss' // local ./theme.scss stylesheets aren't found either interface IAppStateProps { // No props yet } interface IAppDispatchProps { // No state yet } class App extends React.Component<IAppStateProps & IAppDispatchProps, any> { constructor(props: IAppStateProps & IAppDispatchProps) { super(props); } public render() { return ( <div className='wrapper'> <AppBar title='My App Bar' theme={appBarTheme}> </AppBar> </div> ); } } export default App; 

What else is needed to enable import of style sheet modules?

+19
source share
2 answers

TypeScript does not know that there are files other than .ts or .tsx so it will .tsx error if the import has an unknown file suffix.

If you have a webpack configuration that allows you to import other types of files, you must tell the TypeScript compiler that these files exist. To do this, add an announcement file in which you declare modules with matching names.

The contents of the module for the declaration depend on the webpack loader used for the file type. In the configuration of the web package, which *.scss files *.scss via sass-loader β†’ css-loader β†’ style-loader, there will be no content in the imported module, and the correct module declaration will look like this:

 // declaration.d.ts declare module '*.scss'; 

If the loaders are configured for css modules, just expand the declaration as follows:

 // declaration.d.ts declare module '*.scss' { const content: {[className: string]: string}; export default content; } 
+28
source

Here is the complete configuration that works for me (I just spent an hour of painful trial and error on this - in case someone encounters the same problems):

TypeScript + WebPack + Sass

webpack.config.js

 module.exports = { //mode: "production", mode: "development", devtool: "inline-source-map", entry: [ "./src/app.tsx"/*main*/ ], output: { filename: "./bundle.js" // in /dist }, resolve: { // Add '.ts' and '.tsx' as a resolvable extension. extensions: [".ts", ".tsx", ".js", ".css", ".scss"] }, module: { rules: [ { test: /\.tsx?$/, loader: "ts-loader" }, { test: /\.scss$/, use: [ { loader: "style-loader" }, // to inject the result into the DOM as a style block { loader: "css-modules-typescript-loader"}, // to generate a .d.ts module next to the .scss file (also requires a declaration.d.ts with "declare modules '*.scss';" in it to tell TypeScript that "import styles from './styles.scss';" means to load the module "./styles.scss.d.td") { loader: "css-loader", options: { modules: true } }, // to convert the resulting CSS to Javascript to be bundled (modules:true to rename CSS classes in output to cryptic identifiers, except if wrapped in a :global(...) pseudo class) { loader: "sass-loader" }, // to convert SASS to CSS // NOTE: The first build after adding/removing/renaming CSS classes fails, since the newly generated .d.ts typescript module is picked up only later ] }, ] } }; 

Also put the declarations.d.ts file in your project:

 // We need to tell TypeScript that when we write "import styles from './styles.scss' we mean to load a module (to look for a './styles.scss.d.ts'). declare module '*.scss'; 

And you will need all this in your package.json dependencies:

  "devDependencies": { "@types/node-sass": "^4.11.0", "node-sass": "^4.12.0", "css-loader": "^1.0.0", "css-modules-typescript-loader": "^2.0.1", "sass-loader": "^7.1.0", "style-loader": "^0.23.1", "ts-loader": "^5.3.3", "typescript": "^3.4.4", "webpack": "^4.30.0", "webpack-cli": "^3.3.0" } 

Then you should get mystyle.d.ts next to your mystyle.scss containing the CSS classes you define, which you can import as a Typescript module and use like this:

 import * as styles from './mystyles.scss'; const foo = <div className={styles.myClass}>FOO</div>; 

CSS will be automatically loaded (introduced as a style element in the DOM) and will contain cryptic identifiers instead of your CSS classes in .scss to isolate your styles on the page (unless you use :global(.a-global-class) {... } ).

Please note that the first compilation will fail whenever you add CSS classes or delete them or rename them, since the imported mystyles.d.ts is an old version, not a new version, generated only at compilation time. Just compile again.

Enjoy.

0
source

Source: https://habr.com/ru/post/1011949/


All Articles