1. babel-plugin-react-css-modules 简述
在 React 中对于 CSS 的解决方案通常有以下几种:
- Css 命名区间
- Css in Js
- Css Components
- Css Modules
个人比较喜欢使用 CSS Modules 的引入方式,但是其也有不方便的地方,由于其是基于判断 Class 来引入样式的,所以每次定义 Class 时总是需要调用 Css Modules 对象然后读取其某个 Class,如下:
1 | import style from "./style.modules.css" |
同时,使用 Css Module 如果引入了不存在 class 也不会报错。
那么为了解决这一问题,react-css-modules 应运而生,其利用高阶组件的方式去自动将 className 中的样式连接到 CSS Modules 上,这样只需要只需要简单的书写 className 即可:
1 | import style from "./style.modules.css" |
但其仍有缺点,就是该插件是在运行时编译的,在虚拟 DOM 的生成中修改了 className,这样就会消耗客户端一定的性能,同时该插件已经停止维护,因此作者推荐使用 babel-plugin-react-css-modules 来进行替代。
与 react-css-modules 不同的是,babel-plugin-react-css-modules 借助 Babel 可以让 React 应用在构建时就直接替换掉 className 中的值,这样就会极高的提升性能。同时为了与 className 不冲突,babel-plugin-react-css-modules 规定了如果是引用 CSS Modules 中的 class 的话,可以使用 styleName 来进行样式的定义,如:
1 | import "./style.module.css"; |
2. 插件配置
2.1 前期准备
由于在 React 项目中,最常见的脚手架工具为 create-react-app,因此在此以该脚手架工具为示例,演示如何配置 babel-plugin-react-css-modules,并使其支持 less。
首先我们要安装插件:
1 | npm install post-less -D # 对 less 语法进行处理,如果要处理 sass 这里就安装 post-sass |
这里要注意 babel-plugin-react-css-modules 需要作为运行时依赖安装,原因如下:
当babel-plugin-react-css-modules无法在编译时解析CSS模块时,它将导入一个辅助函数(读取运行时styleName解析)。因此,您必须安装babel-plugin-react-css-modules作为项目的直接依赖项。
由于这一部分需要修改 create-react-app 的 webpack 配置,因此我们还要通过逆向工程解构出 webpack 的配置:
1 | yarn run eject |
2.2 修改 babel 配置
babel-plugin-react-css-modules 基于 babel,其也是作为一个 babel 插件使用,所以按照官方文档,我们应该在 .babelrc
文件中配置该插件。由于 create-react-app 将 babel 配置文件集成到了 package.json 中,因此我们需要修改 package.json 的 babel 选项:
1 | // package.json |
这一步的目的是为了让 babel 在编译 js、jsx 文件时,将 JSX 语法中的 styleName 后缀一个 hash 值,并将其添加到 className 中,generateScopedName
选项控制了我们编译后的 className 的格式。同时为了支持 less,需要在 filetypes
选项中添加 postcss-less 以支持读取 less 文件(sass 则是添加 post-sass)。
此外,除了在 .babelrc 以及 package.json 文件中配置 babel 插件之外,我们还可以在 webpack 的 babel-lader 部分来配置这些信息,打开已经结构的 webpack 配置,找到 babel-loader 部分的配置,将其修改为:
1 | // Process application JS with Babel. |
2.3 修改 css-loader 配置
我们目前已经可以使用标签的 styleName 属性了,我们可以在审查元素中看到,使用了 styleName 标签的 DOM 节点上,在 class 中出现了类似 test-bs6rG6AQFi
这样的 className,但此时样式还不会被应用,因为我们现在只处理了 jsx,还未处理 css 文件。
在 css-loader 中有一个 modules 配置选项,该配置项决定了是否开启 css modules,同时规定了 css modules 模式下的一些规范。因此在这一步,我们的目标就是让 css-loader 在处理 css 时启用 css modules 并且 css modules 的 class 命名格式要与 jsx 中的 styleName 处理后的命名格式相同,即都为 [local]-[hash:base64:10]
。
create-react-app 中默认开启了 sass 的 css module,但是没有支持 less,因此我们先将 less 的 loader 添加上,并且开启 css module,同时配置 css-loader 的配置项,让其命名能够一致:
1 | // webpack.config.js |
3. 使用测试
1 | .test { |
1 | import React from "react"; |