6
typescript项目中我们使用typings-for-css-modules-loader来替代css-loader实现css modules。

1、typings-for-css-modules-loader加载器介绍

Webpack加载器,用作css-loader的替代产品,可动态生成CSS模块的TypeScript类型

这句话是什么意思呢?就是编译时处理css文件,为这些css文件生成对应的.d.ts声明文件并且具有css-loader功能,用import/require处理css引用资源(url和@import),使得css模块化,配置modules字段可以启用css modules

为什么需要为css文件生成声明文件呢?因为在typescript项目中无论是我们自己写的代码还是导入第三方库和样式,都应该符合typescript语言规范,就比如在react+typescript项目中,安装了react、react-dom后还得安装@types/react、@types/react-dom,这两个库是react、react-dom的声明文件。

2、typings-for-css-modules-loader加载器使用

typescript项目webpack配置如下:

{
    test: /\.(sc|sa|c)ss$/,
    include: [path.join(__dirname, '../', './src')],
    use: [
      // 'style-loader', // style-loader将第二步编译出来的代码转为js代码
      {
        loader: MiniCssExtractPlugin.loader,
        options: {
          publicPath: (resourcePath, context) => {
            // resourcePath = E:\学习项目\从零搭建typescript+react项目\ts-react\src\index.scss
            // context = E:\学习项目\从零搭建typescript+react项目\ts-react
            return path.relative(path.dirname(resourcePath), context) + '/';
          },
        }
      },
      // css-loader将编译出来的代码再次编译成为符合CommonJS的代码
      {
        loader: 'typings-for-css-modules-loader',
        options: {
          modules: true, // 使用css modules
          namedExport: true, // 类名导出
          camelCase: true, // 支持驼峰
          sass: true, // 是否使用sass
          localIdentName: '[name]__[local]__[hash:base64:5]' // 定义类名
        }
      },
      {
        // 给css加上前缀
        loader: 'postcss-loader',
        options: {
          plugins: [require('autoprefixer')]
        }
      },
      'sass-loader' // sass-loader将sass代码编译为css(默认使用node-sass)
    ]
}

简单解释下三个 Loader 的作用:

  1. sass-loader 的作用当然是把 SASS 文件编译成 CSS 文件;
  2. typings-for-css-modules-loader 是在 css-loader 上包了一层,它的选项完全兼容 css-loader。除此之外,它会为每个 SASS 文件生成对应的 xxx.scss.d.ts 的解释文件,这样在 TypeScript 中就可以正确解析,编辑器里面也能有非常友好的代码提示。
  3. style-loader 就是把样式使用<style>标签打到页面上。

整个过程就是,读到一个 SCSS 文件,丢给 sass-loader(调用node-sass) 处理成 css,然后给 typings-for-css-modules-loader 生成 xxx.scss.d.ts 文件并且把 css 处理成 JavaScript 可以使用的样子(这步其实是 css-loader 在处理,为啥要把 css 文件处理成 JavaScript 可以用的样子呢,因为 webpack 只能处理 JavaScript,所以需要做转换),最后把处理好的给 style-loader,页面加载的时候就会打到页面上。

其实 loader 的本质就是anything to JavaScript,因为 Webpack 只处理 JavaScript。记住这一点,就对为什么要用这个 loader 那个 loader 有个清晰的认识了。

比如在react + typescript项目中,配置好typings-for-css-modules-loader后,我们定义index.scss、index.tsx两个文件,并在index.tsx中导入index.scss样式。由于启用了css modules,所有的样式类名都会以hash字符串替换,如果我们import './index.scss'导入样式,那么只能在元素中className="填写对应类名对应hash字符串",但是类名的hash字符串是编译时生成的,而我们在写代码时并不知道我们需要的类名会编译成哪个hash字符串,并且hash字符串很长不方便书写和记忆。

image.png

我们改用以模块的方式导入样式文件,但这会遇到一个问题TS2307: cannot find module '.xxx',因为样式文件不是AMD/CMD规范文件,不支持模块导入,typescript语法可以使用declare module声明模块,我们定义一个.d.ts文件,然后写样式模块声明,项目编译过程中会自动去读取.d.ts这种类型的文件,所以不需要我们手动地加载他们。当然.d.ts文件也不能随便放置在项目中,这类文件和ts文件一样需要被typescript编译,所以一样只能放置在tsconfig.jsoninclude属性所配置的文件夹下。

// typed-css.d.ts
// scss模块声明
declare module '*.scss' {
  const content: {[key: string]: any}
  export = content
}
// less模块声明
declare module '*.less' {
  const content: { [key: string]: any }
  export default content
}

这样,样式文件就可以使用模块导入的方式了。

image.png

参考:
https://blog.csdn.net/weixin_...
https://www.npmjs.com/package...


记得要微笑
1.9k 声望4.5k 粉丝

知不足而奋进,望远山而前行,卯足劲,不减热爱。