webpack 自动识别 css modules(cssModule混用)
期望达到的效果
import Test from './test.less'; // 这样的引入需要css modules
import './test.less'; // 这样的不需要css modules
虽然 css-loader 自带一些配置可以用来配置是否开启当前文件cssModule(配置特殊的文件名,路径等),但是还是觉得没有上面的那种用起来方便。
参考 umi css module 的实现,源码:babel-plugin-auto-css-modules,通过写 Babel 插件,在 import 的 url 上加上参数,webpack 匹配这个参数,进行不同的配置。
这样的引入方式也可以消除开启 css module 后,ant design 组件样式出错的问题。
Babel 插件
// scripts/plugin/auto-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/preset-react",
"@babel/preset-env",
"@babel/preset-typescript"
],
"plugins": [
"@babel/plugin-transform-runtime",
"@babel/plugin-proposal-class-properties",
"lodash",
"./scripts/plugin/auto-css-modules.js", // 引入插件
["import", {
"libraryName": "antd",
"libraryDirectory": "es",
"style": "css"
}]
]
}
在 webpack 中进行配置
声明两个不同的loader配置
// 未开启 css module 的 loader
const cssLoader = [
'style-loader',
!isEnvDevelopment && {
loader: MiniCssExtractPlugin.loader,
},
'css-loader',
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
require('postcss-preset-env')({
autoprefixer: {
flexbox: 'no-2009',
},
stage: 3,
}),
],
},
},
{
loader: 'less-loader',
options: {
javascriptEnabled: true,
},
},
];
// 开启 css module 的 loader
const cssModulesLoader = JSON.parse(JSON.stringify(cssLoader));
cssModulesLoader[2] = {
loader: 'css-loader',
options: {
modules: {
localIdentName: '[local]_[hash:base64:5]',
},
},
};
webpack rules 配置:
module: {
rules: [
{
test: /\.(css|less)$/,
oneOf: [
{
resourceQuery: /css_modules/, // 只要匹配到了这个,就是用css modules,
use: cssModulesLoader.filter(Boolean),
},
{
use: cssLoader.filter(Boolean),
},
],
},
]
}
这样配置后,就可以在项目中查看具体的效果了。。。。。