用react-app-rewire来同时使用antd(-mobile)的less和css modules 作者: Semesse 时间: 2018-08-01 分类: Javascript 不使用 eject 真是一件非常麻烦的事,因为 webpack 的配置没有暴露出来,所以没法直接修改 虽然有 react-app-rewire-css-modules 这样的库在,但是引入一些乱七八糟又长又臭的库显然不是一个好选择,而且别人是给 css[sass/scss] 写的,要引入 sass-loader,又没有 less 支持 所以这里我们只能自己动手,丰衣足食 如果跟着 antd 的按需引入教程走的话,应该会有一个 config-override.js 文件 ```js module.exports = function override(config, env) { //这里引入的是antd-mobile config = injectBabelPlugin(['import', { libraryName: 'antd-mobile', style: true }], config); return config; }; ``` * 如果要使用 antd 的自定义主题色的话,按照官方教程需要引入 react-app-rewire-less 库,但是这个库的功能不够(没法 exclude 之类),而且我们可以很容易实现它,所以这里不引入 我们要做的事情就是修改 config,但是我们不太清楚里面是 webpack 的配置大概长什么样,所以需要 console.log 然后每次 npm run start 的时候检查里面的东西(误 其实我新建了一个工程然后 npm run eject 来查看 webpack 配置, 在 module.rules 中可以找到一段这样的配置,这就是我们要改的东西 ```js { test: /\.css$/, use: [ require.resolve('style-loader'), { loader: require.resolve('css-loader'), options: { importLoaders: 1, }, }, { loader: require.resolve('postcss-loader'), options: { // Necessary for external CSS imports to work // https://github.com/facebookincubator/create-react-app/issues/2677 ident: 'postcss', plugins: () => [ require('postcss-flexbugs-fixes'), autoprefixer({ browsers: [ '>1%', 'last 4 versions', 'Firefox ESR', 'not ie < 9', // React doesn't support IE8 anyway ], flexbox: 'no-2009', }), ], }, }, ], } ``` 首先我们写个函数接受 config 并修改它(所以我们其实不需要 immutable ,不需要纯函数,对吧? const useLessCSSModules= function (config) { return config } 我们得先找到这一条 css 规则 const useLessCSSModules = function (config) { let indexOfCSSRule let cssRule = config.module.rules[1].oneOf.filter((rule, index) => { if (rule.test && String(rule.test) === String(/\.css$/)) { indexOfCSSRule = index return true } else { return false } })[0] return config } 让它可以匹配 less 文件 cssRule.test = /\.(css|less)/ cssRule.use.push({ loader: require.resolve('less-loader'), options: { javascriptEnabled: true, modifyVars: theme } }) * modifyVars 是用来自定义 antd 主题色的,此处可以去掉 最后用 lodash.deepclone 复制一份规则,其中一份包含 node_modules文件夹不加 css modules,另一份排除 node_modules文件夹并添加 css modules let noCSSModule = clone(cssRule) noCSSModule.include = require('path').resolve(__dirname, './node_modules') config.module.rules[1].oneOf.splice(indexOfCSSRule+1, 0, noCSSModule) cssRule.exclude = require('path').resolve(__dirname, './node_modules') let cssLoader = cssRule.use.filter(loader => /\\css-loader\\/.test(loader.loader))[0] cssLoader.options = Object.assign({ modules: true, localIdentName: '[name]__[local]-[hash:base64:5]' },cssLoader.options) 最后的成品 const { injectBabelPlugin } = require('react-app-rewired'); const theme = require('./src/theme') const useLessCSSModules = function (config) { const clone = require('lodash.clonedeep') let indexOfCSSRule let cssRule = config.module.rules[1].oneOf.filter((rule, index) => { if (rule.test && String(rule.test) === String(/\.css$/)) { indexOfCSSRule = index return true } else { return false } })[0] cssRule.test = /\.(css|less)/ cssRule.use.push({ loader: require.resolve('less-loader'), options: { javascriptEnabled: true, modifyVars: theme } }) // add a new rule for node_modules let noCSSModule = clone(cssRule) noCSSModule.include = require('path').resolve(__dirname, './node_modules') config.module.rules[1].oneOf.splice(indexOfCSSRule+1, 0, noCSSModule) cssRule.exclude = require('path').resolve(__dirname, './node_modules') let cssLoader = cssRule.use.filter(loader => /\\css-loader\\/.test(loader.loader))[0] cssLoader.options = Object.assign({ modules: true, localIdentName: '[name]__[local]-[hash:base64:5]' },cssLoader.options) return config } module.exports = function override(config, env) { //antd-mobile config = injectBabelPlugin(['import', { libraryName: 'antd-mobile', style: true }], config); //css modules config = useLessCSSModules(config) return config; }; 标签: React, webpack