前言
css module
的好处是可以避免 namespace
冲突的问题,尤其是项目工程比较庞大的情况。今天在自己搭建的react项目中想用import cls from 'XXX.css'
导入css modules
样式的时候,发现页面出现以下情况 ↓ , 打印了一下才发现cls = underfined
原因:
css-loader
的optons.modules
配置默认是undefined
,需要匹配特定的正则才能启用css modules
关键问题
- Question: 正常的启用
modules
会让想作为全局的样式失去效果,因为都被转成唯一值了, 不全局开启只能规定后缀名去区分使用css modules
- 正确做法:让
webpack
自动识别是否启用css modules
思路
最终目标:根据规则匹配在css-loader中开启modules
- 区分是否启用
css modules
,其实就是区分import './index.css'
和import cls from './index.css'
,看看对应转成AST哪里有区别 - 根据这个不同的字段去给启用
css modules
的文件打标签 - 用
webpack
的rules
规则匹配字段oneOf进行匹配
参考 umi css module 的实现
源码:babel-plugin-auto-css-modules,通过写 Babel
插件,在 import
的 url
上加上参数,webpack
匹配这个参数,进行不同的配置。
babel插件
// babel插件 --- css-modules.js
const { extname } = require("path");
const CSS_EXTNAMES = [".css", ".scss", ".sass", ".less"];
module.exports = () => {
return {
visitor: {
ImportDeclaration(path) {
const { specifiers, source } = path.node;
const { value } = source;
if (specifiers.length > 0 && CSS_EXTNAMES.includes(extname(value))) {
source.value = `${value}?css_modules`; // 在路径末尾加上 css_modules 用于 webpack 匹配该文件,如 import Test from './test.less'; 变成 import Test from './test.less?css_modules';
}
},
},
};
};
复制代码
在.babelrc
中引入插件
{
"presets": [
"@babel/env",
[
"@babel/preset-react",
{"runtime": "automatic"}
],
],
"plugins": ["./css-modules"]
}
复制代码
测试插件是否有效引入
if (
specifiers.length > 0 &&
CSS_FILE_EXTENSIONS.includes(extname(value))
) {
console.log(value); // 启动webpack 有看到打印值就可以了
source.value = `${value}?css_modules`;
}
复制代码
配置webpack
的rules
const rules = [
{
test: /\.(js|jsx|ts|tsx)$/,
exclude: /(node_modules|bower_components)/,
use: 'babel-loader',
},
{
test: /\.css$/,
oneOf: [
{
resourceQuery: /css_modules/,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader', options: { modules: true } },
// { loader: 'less-loader' }, less加上即可
],
},
{
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' },
//{ loader: 'less-loader' },
],
},
],
},
];
复制代码
利用 resourceQuery 的能力,查询是否存在特定的参数,来决定是否启用
css-module
的功能。达到了不用修改文件名的形式,兼容了普通css
和css-module
的样式文件,简单而优雅:)
最终效果
不用特殊后缀名也可以正常使用css modules,全局样式也正常插入DOM中,prefect。