如何在Typescript、React和Webpack中导入CSS模块

104

如何在Webpack中使用TypeScript导入CSS模块?

  1. 生成(或自动生成)CSS的.d.ts文件,然后使用经典的TypeScriptimport语句并引用./styles.css.d.ts

  2. import * as styles from './styles.css'
    
  3. 使用require函数导入Webpack模块?

    let styles = require("./styles.css");
    

但对于最后一种方法,我必须定义require函数。

什么是最佳方法或最佳选项,并且还可以处理CSS文件定义和类的智能感知?


1
任一种 import * as styles from ...import styles = require(... 都是有效的。你可能需要为你的 CSS 文件声明一个模块,无论是显式的还是通用的所有 CSS 文件都可以,因为 TypeScript 编译器对此一无所知。请参见这里以获取自动生成定义的生成器。 - Meirion Hughes
9个回答

96

现在在2021年,您所需做的就是在项目中添加一个src/Globals.d.ts文件,并包含以下内容:

declare module "*.module.css";
declare module "*.module.scss";
// and so on for whatever flavor of css you're using

然后安装并添加

{
  "compilerOptions": {
    "plugins": [{ "name": "typescript-plugin-css-modules" }]
  }
}

将此更改正确添加到您的 tsconfig 文件中的示例(root 是我样式表中定义的类):

enter image description here

Webpack 和 tsc 也可以在命令行上正确编译。


3
“src/Globals.d.ts” 不是 “src/Gobals.d.ts”,对吧?需要确认一下? - Dom
4
这个很棒,谢谢!还有,谢谢 @Dom 的提醒,是Globals而不是Gobals,哈哈! - Hank
3
如果您有兴趣,也可以查看这篇博客文章 https://spin.atomicobject.com/2020/06/22/css-module-typescript/#comment-680455 - Felix Orinda
3
这个解决方案现在也适用于2023年!;) - jpxcar
在 tsconfig 中添加行后,需要在终端执行任何命令吗? - Shikha
2
有一个重要步骤缺失:确保 VS Code 使用项目的 TypeScript 版本而不是 VS Code 版本。如果在 Vscode 文件夹级别设置中添加 setting.json 文件无效,请尝试使用工作区级别设置。或者,在 Vscode 中更改设置:**TypeScript: 选择 TypeScript 版本...。有关使用图表**的说明,请参阅 https://puruvj.dev/blog/css-modules-typescript-intellisense#Set-VSCode-TypeScript-version - Nor.Z

58

A) 就像你所说,使用 require 的最简单选项(不是最好的)有一种:

const css = require('./component.css')
  • 由于TypeScript中没有标准的功能,我们需要为require编写类型定义。
  • 这个特定的require最简单的类型定义可能是:

declare function require(name: string): string;
  • Webpack将编译TypeScript并正确使用模块 - 但是在构建时没有任何IDE帮助和类名检查

  • B) 有更好的解决方案可以使用标准import

    import * as css from './component.css'
    
    • 启用完整的类名 IntelliSense
    • 每个CSS文件都需要类型定义,否则tsc编译器将失败

    为了正确的 IntelliSense,Webpack 需要为每个 CSS 文件生成类型定义:

    1. 使用 webpack typings-for-css-modules-loader

    webpackConfig.module.loaders: [
      { test: /\.css$/, loader: 'typings-for-css-modules?modules' }
      { test: /\.scss$/, loader: 'typings-for-css-modules?modules&sass' }
    ];
    
  • Loader将为代码库中的每个CSS文件生成*.css.d.ts文件。

  • Typescript编译器将理解CSS导入将是具有类型为字符串的属性(类名)的模块。
  • 提到的typings-for-css-loader包含一个错误,由于类型文件生成的延迟,最好在我们的*.css.d.ts文件尚未生成时声明全局*.css类型。

    那种小错误场景:

    1. 创建CSS文件component.css
    2. 在组件中包含它import * as css from './component.css'
    3. 运行webpack
    4. Typescript编译器将尝试编译代码(错误)
    5. 加载器将生成Css模块类型文件(component.css.d.ts),但对于Typescript编译器来说太晚了,找不到新的类型文件。
    6. 再次运行webpack将修复构建错误。

    简单的解决方法是为导入CSS模块创建全局定义(例如,在源根目录中创建一个名为typings.d.ts的文件):

    declare module '*.css' {
      interface IClassNames {
        [className: string]: string
      }
      const classNames: IClassNames;
      export = classNames;
    }
    

    如果没有生成CSS文件(例如,您添加了新的CSS文件),则会使用此定义。否则,将使用生成的特定(需要在同一文件夹中命名与源文件相同并以.d.ts扩展名),例如component.css.d.ts定义,IntelliSense将完美地工作。

    component.css.d.ts的示例:

    export const wrapper: string;
    export const button: string;
    export const link: string;
    

    如果你不想看到生成的 CSS 类型文件,你可以在 IDE 中设置过滤器,隐藏所有扩展名为 .css.d.ts 的源文件。


    37

    我已经将一个名为Global.d.tstypings.d.ts的文件添加到了我的./src文件夹中,其中包含一些类型定义:

    declare module "*.module.css";
    

    Webpack的CSS配置:

    {
      test: /\.css$/,
      use: [
        isProductionBuild ? MiniCssExtractPlugin.loader : "style-loader",
        {
          loader: "css-loader",
          options: {
            modules: true,
            importLoaders: 1,
            localIdentName: "[name]_[local]_[hash:base64]",
            sourceMap: true,
            minimize: true
          }
        }
      ]
    },
    

    然后我只需要像这样导入模块:import styles from "./App.module.css";


    3
    补充一下,如果你正在使用带有--typescript标志的create-react-app,并且他们的webpack配置期望CSS模块命名为*.module.css。因此,你只需将所有.css文件重命名为File.module.css,然后像这样导入它们import styles from "./File.module.css",就可以使“从b中导入a”语法起作用了。 - Galen Long

    21

    在2022年,我所需要做的就是在src文件夹下添加Globals.d.ts文件。

    declare module "*.module.css";
    declare module "*.module.scss";
    

    然后我可以像通常一样在我的TypeScript文件中导入CSS模块,用于css或scss文件:

    import styles from "./Team.module.scss";
    

    错误:未找到模块 - undefined

    3

    或者使用 require webpack 函数导入

    这是我以前常用的方法,现在我的一些项目中仍然保留着这段代码。


    现在:我写了 typestyle:http://typestyle.github.io/#/ 但你并不一定要使用它。如果你愿意,可以继续使用 const styles = require('./styles.css')。另外,如果需要,你也可以在 typestyle 中使用原始 CSS:http://typestyle.github.io/#/raw


    2
    这个案例涉及到TypeScript。您可以在项目中添加一个名为typings.d.ts的文件,并将以下内容复制进去:
    declare module "*.module.css";
    declare module "*.module.scss";
    

    如果您想启用CSS模块化,使用文件名格式为*.module.*是一个好的实践。

    css-loader将自动为符合以下正则表达式的文件启用CSS模块化:/\.module\.\w+$/i。可以通过将options.modules属性设置为对象来自定义此功能。

    例如:

    import style from './App.module.css'; // CSS Module enabled
    import './index.css'; // Plain CSS loaded
    

    对于最近的配置,您可以将此规则添加到webpack.config.js中:

    {
      test: /\.css$/,
      use: [
        'style-loader',
        {
          loader: "css-loader",
          options: {
            modules: {
              localIdentName: "[hash:base64]", // default
              auto: true // default
            },
            sourceMap: true
          }
        },
      ]
    },
    
    

    一份自定义配置示例:
    {
      loader: "css-loader",
      options: {
        modules: {
          localIdentName: "[name]_[local]_[hash:base64]", // custom class name format
          auto: /\.cmod\.\w+$/i, // custom auto enable CSS Module for "*.cmod.css" format
        },
      }
    },
    
    

    完整文档在这里


    使用.module.css是一个好的实践吗?还是必须使用它?因为如果不是必须的,那么让人们使用这种荒谬的命名约定并不是一个好的实践。 - Cale McCollough
    它已经被流行的库(如CSS Loader或Angular)广泛使用,以检测应用CSS模块的文件。因此,与社区保持一致是一个好习惯。该名称也是可接受且易于区分的。 - Luki B. Subekti

    2
    我认为现在TypeScript可以通过以下方式简单地导入CSS文件: import '要导入的文件路径.css'

    2

    我使用了create-react-app,但由于某些原因其他解决方案都不起作用,似乎缺少了一些东西;我认为这是因为VS Code使用了自己的TypeScript版本。所以这就是我做的所有事情,直到最终它终于起作用了;如果你也使用create-react-appVS Code,那么它应该也适用于你:

    1. 运行npm i typescript-plugin-css-modules --save-dev
    2. 在项目的根目录中创建一个名为styles.d.ts(或类似名称)的文件,并粘贴以下内容:

    styles.d.ts

    // if you use css
    declare module "*.module.css" {
      const classes: { [key: string]: string };
      export default classes;
    }
    
    // if you use scss
    declare module "*.module.scss" {
      const classes: { [key: string]: string };
      export default classes;
    }
    
    // if you use less
    declare module "*.module.less" {
      const classes: { [key: string]: string };
      export default classes;
    }
    
    1. 在 .vscode/settings.json 中(如果没有该文件,请创建)- 添加以下字段:

    .vscode/settings.json

    "typescript.tsdk": "node_modules/typescript/lib",
    "typescript.enablePromptUseWorkspaceTsdk": true
    

    因此,文件可能看起来像这样:

    .vscode/settings.json

    {
       "typescript.tsdk": "node_modules/typescript/lib",
       "typescript.enablePromptUseWorkspaceTsdk": true
    }
    

    -11

    let styles = require("./styles.css"); 是最佳的方法,因为它是 JavaScript 的 es5 版本,与 React 的每个功能兼容。import * as styles from './styles.css' 是 JavaScript 的 es6 版本。


    1
    这不是ES5或ES6,而是TypeScript,因此将进行转译。 - Meirion Hughes
    我同意@Meirion Hughes的观点。感谢所有人的回复! - Diego Laciar

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接