web-dev-qa-db-fra.com

Impossible d'importer des modules CSS / SCSS. TypeScript dit "Impossible de trouver le module"

J'essaie d'importer un thème à partir d'un module CSS mais TypeScript me donne une erreur "Impossible de trouver le module" et le thème n'est pas appliqué au moment de l'exécution. Je pense qu'il y a un problème avec ma configuration Webpack mais je ne sais pas où est le problème.

J'utilise les outils suivants:

"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"

Voici mon 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: './'
  },
};

et mon App.tsx où j'essaye d'importer:

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;

Que faut-il d'autre pour activer l'importation du module de feuille de style de typesafe?

27
zakdances

TypeScript ne sait pas qu'il existe des fichiers autres que .tsou .tsx donc il générera une erreur si une importation a un suffixe de fichier inconnu.

Si vous avez une configuration de webpack qui vous permet d'importer d'autres types de fichiers, vous devez indiquer au compilateur TypeScript que ces fichiers existent. Pour ce faire, ajoutez un fichier de déclaration dans lequel vous déclarez les modules avec des noms appropriés.

Le contenu du module à déclarer dépend du chargeur de webpack utilisé pour le type de fichier. Dans une configuration de webpack qui canalise *.scss fichiers via sass-loadercss-loaderstyle-loader, il n'y aura pas de contenu dans le module importé, et le bon La déclaration du module ressemblerait à ceci:

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

Si les chargeurs sont configurés pour les modules css, étendez simplement la déclaration comme ceci:

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

Voici une configuration complète qui fonctionne pour moi (je viens de passer une heure d'épreuves et d'erreurs douloureuses à ce sujet - au cas où quelqu'un rencontrerait les mêmes problèmes):

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
            ] }, 

        ]
    }
}; 

Mettez également un declarations.d.ts Dans votre projet:

// 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'; 

Et vous en aurez besoin dans les dépendances de développement de votre package.json:

  "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"
  }

Ensuite, vous devriez obtenir un mystyle.d.ts À côté de votre mystyle.scss Contenant les classes CSS que vous avez définies, que vous pouvez importer en tant que module TypeScript et utiliser comme ceci:

import * as styles from './mystyles.scss'; 

const foo = <div className={styles.myClass}>FOO</div>; 

Le CSS sera automatiquement chargé (injecté en tant qu'élément style dans le DOM) et contiendra des identificateurs cryptiques au lieu de vos classes CSS dans le .scss, pour isoler vos styles dans la page (à moins que vous n'utilisiez la fonction :global(.a-global-class) { ... }).

Notez que la première compilation échouera chaque fois que vous ajoutez des classes CSS, les supprimez ou les renommez, car le mystyles.d.ts importé est l'ancienne version et non la nouvelle version juste générée pendant la compilation. Compilez à nouveau.

Prendre plaisir.

8
frevd