Не вдається імпортувати модулі CSS / SCSS. TypeScript говорить “Не вдається знайти модуль”


88

Я намагаюся імпортувати тему з модуля CSS, але TypeScript видає помилку "Не вдається знайти модуль", і тема не застосовується під час виконання. Я думаю, що щось не так з моєю конфігурацією Webpack, але я не впевнений, де проблема.

Я використовую такі інструменти:

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

Ось моя 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: './'
  },
};

і мій, App.tsxде я намагаюся імпортувати:

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;

Що ще потрібно, щоб увімкнути імпорт модуля таблиці стилів із безпечним типом?

Відповіді:


125

TypeScript не знає, що існують інші файли, окрім цього, .tsабо .tsxце призводить до помилки, якщо імпорт має невідомий суфікс файлу.

Якщо у вас є конфігурація webpack, яка дозволяє імпортувати файли інших типів, вам слід повідомити компілятор TypeScript, що ці файли існують. Для цього додайте файл декларації, в якому ви оголошуєте модулі з відповідними іменами.

Вміст оголошеного модуля залежить від завантажувача webpack, що використовується для типу файлу. У конфігурації webpack, яка передає *.scssфайли через sass-loadercss-loaderstyle-loader , в імпортованому модулі не буде вмісту, і правильна декларація модуля буде виглядати так:

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

Якщо завантажувачі налаштовані на css-модулі, просто розширіть декларацію так:

// declaration.d.ts
declare module '*.scss' {
    const content: Record<string, string>;
    export default content;
}

2
Гей, це у мене не спрацювало, щось недавно змінилося. stackoverflow.com/questions/56563243/…
Кей

50

Ось повна конфігурація, яка працює для мене (я просто витратив на це годину болісних спроб і помилок - на випадок, якщо хтось зіткнеться з тими ж проблемами):

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

        ]
    }
}; 

Також поставте declarations.d.tsу свій проект:

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

І все це вам знадобиться у ваших 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"
  }

Тоді ви повинні отримати mystyle.d.tsпоруч із вашим, mystyle.scssщо містить визначені вами класи CSS, які ви можете імпортувати як модуль Typescript і використовувати так:

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

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

CSS буде автоматично завантажений (введений як styleелемент у DOM) і міститиме загадкові ідентифікатори замість ваших класів CSS у .scss, щоб ізолювати ваші стилі на сторінці (якщо ви не використовуєте:global(.a-global-class) { ... } ).

Зверніть увагу, що перша компіляція зазнає невдачі кожного разу, коли ви додаєте класи CSS або видаляєте їх або перейменовуєте, оскільки імпортований mystyles.d.ts є старою версією, а не новою версією, щойно створеною під час компіляції. Просто скомпілюйте ще раз.

Насолоджуйтесь.


"ПРИМІТКА: Перша збірка після додавання / видалення / перейменування класів CSS не вдається, оскільки нещодавно згенерований модуль .d.ts typecript піднімається лише пізніше" - Як вирішити цю частину?
Джон Лаурідсен,

3
@JonLauridsen це можна вирішити, встановивши ts-loader внизу (в кінці) масиву правил у webpack.config.js. Таким чином, ts-loader підбере правильні * .scss.d.ts файли кожної компіляції, оскільки вони будуть створені раніше.
Ян Пак,

1
@YanPak Дякую, додавши a global.d.tsдо мого srcкаталогу разом із переміщенням ts-loader нижче стилів завантажувачів, це виправлено для мене.
люкс

5

Зверніть увагу, якщо ви використовуєте налаштування шляху tsconfig.json

Зверніть увагу, що якщо ви використовуєте ці рішення разом із tsconfig-шляхами для скорочення імпорту, вам знадобиться додаткова конфігурація.

Якщо ви випадково використовуєте такий шлях tsconfig:

{
  "compilerOptions": {
    "paths": {
      "style/*": [ "src/style/*" ],
    }
  }
}

Отже, ви можете зробити:

import { header } from 'style/ui.scss';

Потім вам потрібно також додати модулі для розв'язання конфігурації у вашому веб-пакеті, наприклад:

module.exports = {
  ...
  resolve: {
    ...
    alias: {
      style: path.resolve(__dirname, 'src', 'style')
    }
  }
}

Переконайтеся, що шлях встановлено відповідно до ваших налаштувань.

Це робить так, що webpack знає, куди шукати, оскільки вважає, що новий шлях імпорту насправді є модулем, тому за замовчуванням він має каталог node_modules. За допомогою цієї конфігурації він знає, де шукати, і знаходить його, і збірка працює.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.