Không thể nhập mô-đun CSS / SCSS. TypeScript cho biết “Không thể tìm thấy mô-đun”


82

Tôi đang cố nhập chủ đề từ mô-đun CSS nhưng TypeScript cho tôi lỗi "Không thể tìm thấy mô-đun" và chủ đề không được áp dụng trong thời gian chạy. Tôi nghĩ có điều gì đó không ổn với cấu hình Webpack của mình nhưng tôi không chắc vấn đề nằm ở đâu.

Tôi đang sử dụng các công cụ sau:

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

Đây là 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.tsxnơi tôi đang cố gắng nhập:

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;

Cần thêm gì nữa để kích hoạt tính năng nhập mô-đun biểu định kiểu an toàn?

Câu trả lời:


120

TypeScript không biết rằng có các tệp khác .tshoặc .tsxvì vậy nó sẽ gây ra lỗi nếu một lần nhập có hậu tố tệp không xác định.

Nếu bạn có cấu hình webpack cho phép bạn nhập các loại tệp khác, bạn phải cho trình biên dịch TypeScript biết rằng các tệp này tồn tại. Để làm như vậy, hãy thêm một tệp khai báo trong đó bạn khai báo các mô-đun có tên phù hợp.

Nội dung của mô-đun cần khai báo phụ thuộc vào trình tải webpack được sử dụng cho loại tệp. Trong cấu hình webpack đưa *.scsstệp qua sass-loadercss-loaderstyle-loader , sẽ không có nội dung nào trong mô-đun được nhập và khai báo mô-đun chính xác sẽ trông như sau:

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

Nếu bộ tải được cấu hình cho css-module chỉ cần mở rộng khai báo như sau:

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

1
Này, điều này đã không làm việc cho tôi, có một cái gì đó gần đây đã thay đổi. stackoverflow.com/questions/56563243/…
Kay

45

Đây là một cấu hình hoàn chỉnh phù hợp với tôi (Tôi vừa trải qua một giờ thử nghiệm và gặp lỗi đau đớn về điều này - trong trường hợp có ai gặp phải vấn đề tương tự):

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

        ]
    }
}; 

Cũng đặt một declarations.d.tstrong dự án của bạn:

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

Và bạn sẽ cần tất cả những thứ này trong package.jsonphần phụ thuộc nhà phát triển của bạn:

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

Sau đó, bạn sẽ nhận được một mystyle.d.tsbên cạnh mystyle.scsschứa các lớp CSS mà bạn đã xác định, bạn có thể nhập các lớp này dưới dạng mô-đun Typecript và sử dụng như sau:

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

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

CSS sẽ tự động được tải (được đưa vào dưới dạng một stylephần tử vào DOM) và chứa các số nhận dạng khó hiểu thay vì các lớp CSS của bạn trong .scss, để tách biệt các kiểu của bạn trong trang (trừ khi bạn sử dụng :global(.a-global-class) { ... }).

Lưu ý rằng lần biên dịch đầu tiên sẽ không thành công bất cứ khi nào bạn thêm các lớp CSS hoặc xóa chúng hoặc đổi tên chúng, vì mystyles.d.ts đã nhập là phiên bản cũ chứ không phải phiên bản mới vừa được tạo trong quá trình biên dịch. Chỉ cần biên dịch lại.

Thưởng thức.


"LƯU Ý: Bản dựng đầu tiên sau khi thêm / xóa / đổi tên lớp CSS không thành công, vì mô-đun typecript .d.ts mới được tạo chỉ được chọn sau này" - Làm thế nào để giải quyết phần đó?
Jon Lauridsen

3
@JonLauridsen nó có thể được giải quyết bằng cách đặt ts-loader ở cuối (cuối) mảng quy tắc trong webpack.config.js. Vì vậy, ts-loader sẽ nhận một tệp * .scss.d.ts chính xác mỗi khi biên dịch vì chúng sẽ được tạo trước đó.
Yan Pak

1
@YanPak Cảm ơn, đã thêm a global.d.tsvào srcthư mục của tôi cùng với việc di chuyển trình tải ts xuống bên dưới trình tải kiểu đã sửa lỗi cho tôi.
lux

4

Lưu ý nếu bạn đang sử dụng thiết lập đường dẫn tsconfig.json

Lưu ý rằng nếu bạn đang sử dụng các giải pháp này cùng với các đường dẫn tsconfig để rút ngắn quá trình nhập của mình, bạn sẽ cần cấu hình bổ sung.

Nếu bạn tình cờ sử dụng một đường dẫn tsconfig như vậy:

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

Vì vậy, bạn có thể làm:

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

Sau đó, bạn cũng cần thêm cấu hình giải quyết mô-đun trên gói web của mình như sau:

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

Đảm bảo rằng đường dẫn được đặt theo thiết lập của bạn.

Điều này giúp webpack biết phải tìm ở đâu vì nó nghĩ rằng đường dẫn nhập mới thực sự là một mô-đun nên nó được đặt mặc định là thư mục node_modules. Với cấu hình này, nó biết nơi để tìm và tìm thấy nó và công trình xây dựng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.