你可能也会遇到的Craco React Less Module问题

3,322 阅读2分钟

起因

自己在用 react-create-app脚手架创建项目时,用到less 模块化导入,即import styles from './login.module.less',发现自己在TSX中引用时报错。

初始条件,自己可以参照 antd官网,我是用的typescript写的

yarn add @craco/craco

然后在项目根目录创建一个 craco.config.js 用于修改默认配置

自己网上百度参考,然后自己总结了如下改动,希望能帮到你

第一种方式

简单粗暴;自己发现craco-less,这个插件默认排除了 /\.module\.(less)$/;详细的自己可以研究下craco-less源码

image.png

/* eslint-disable @typescript-eslint/no-var-requires */
const CracoAntDesignPlugin = require('craco-antd')
const CracoLessPlugin = require('craco-less')
const { resolve } = require('path')

module.exports = {
  plugins: [
    {
      plugin: CracoAntDesignPlugin,
      options: {
        customizeTheme: {
          '@primary-color': '#1DA57A'
        }
      }
    },
    {
      plugin: CracoLessPlugin,
      options: {
        modifyLessRule: (lessRule, context) => {
          return {
            test: /\.less$/,
            use: [
              'style-loader',
              {
                loader: 'css-loader',
                options: {
                  modules: 
                    localIdentName: '[path][name]__[local]'
                  }
                }
              },
              'less-loader'
            ]
          }
        }
      }
    }
  ],
  webpack: {
    alias: {
      '@': resolve(__dirname, 'src')
    }
  }
}

直接重写less规则

localIdentName解释 支持的模板字符串:

  • [name] 源文件名称
  • [path] 源文件相对于 compiler.context 或者 modules.localIdentContext 配置项的相对路径。
  • [file] - 文件名和路径。
  • [ext] - 文件拓展名。
  • [hash] - 字符串的哈希值。基于 localIdentHashSaltlocalIdentHashFunctionlocalIdentHashDigestlocalIdentHashDigestLengthlocalIdentContextresourcePath 和 exportName 生成。
  • [<hashFunction>:hash:<hashDigest>:<hashDigestLength>] - 带有哈希设置的哈希。
  • [local] - 原始类名

建议:

  • 开发环境使用 '[path][name]__[local]'
  • 生产环境使用 '[hash:base64]'

第二种方式

/* eslint-disable @typescript-eslint/no-var-requires */
const CracoAntDesignPlugin = require('craco-antd')
const { resolve } = require('path')


/* craco-plugin-webpack-config.js */
const lessConfig = {
  overrideWebpackConfig: ({
    webpackConfig,
    cracoConfig,
    pluginOptions,
    context: { env, paths }
  }) => {
    if (pluginOptions.preText) {
      console.log(pluginOptions.preText)
    }
    const oneOfRule = webpackConfig.module.rules.find((rule) => rule.oneOf)
      
    oneOfRule.oneOf.push({
      test: /\.module\.(less)$/,
      use: [
        {
          loader: 'style-loader'
        },
        {
          loader: 'css-loader',
          options: {
            importLoaders: 3,
            sourceMap: true,
            modules: {
              localIdentName: '[path][name]__[local]'
            }
          }
        },
        'less-loader'
      ]
    })

    // Always return the config object.
    return webpackConfig
  }
}

module.exports = {
  plugins: [
    {
      plugin: CracoAntDesignPlugin,
      options: {
        customizeTheme: {
          '@primary-color': '#1DA57A'
        }
      }
    },
    {
      plugin: lessConfig,
      options: { preText: 'Will log the craco config:' }
    }
  ],
  webpack: {
    alias: {
      '@': resolve(__dirname, 'src')
    }
  }
}

cacro Less导入全局变量

const {
  getLoader,
  loaderByName,
  addBeforeLoader,
  addAfterLoader,
  throwUnexpectedConfigError
} = require('@craco/craco')

const styleResourcesLoader = {
  loader: 'style-resources-loader',
  options: {
    patterns: resolve(__dirname, './src/styles/index.less'),
    injector: 'append'
  }
}
addAfterLoader(
  webpackConfig,
  loaderByName('less-loader'),
  styleResourcesLoader
)

完整配置

/* eslint-disable @typescript-eslint/no-var-requires */
const CracoAntDesignPlugin = require('craco-antd')
const CracoLessPlugin = require('craco-less')
const { resolve } = require('path')
const {
  getLoader,
  loaderByName,
  addBeforeLoader,
  addAfterLoader
} = require('@craco/craco')

/* craco-plugin-log-webpack-config.js */
const lessConfig = {
  overrideWebpackConfig: ({
    webpackConfig,
    cracoConfig,
    pluginOptions,
    context: { env, paths }
  }) => {
    if (pluginOptions.preText) {
      console.log(pluginOptions.preText)
    }

    const oneOfRule = webpackConfig.module.rules.find((rule) => rule.oneOf)

    const styleResourcesLoader = {
      loader: 'style-resources-loader',
      options: {
        patterns: resolve(__dirname, './src/styles/index.less'),
        injector: 'append'
      }
    }
    addAfterLoader(
      webpackConfig,
      loaderByName('less-loader'),
      styleResourcesLoader
    )
    oneOfRule.oneOf.push({
      test: /\.module\.(less)$/,
      use: [
        {
          loader: 'style-loader'
        },
        {
          loader: 'css-loader',
          options: {
            importLoaders: 3,
            sourceMap: true,
            modules: {
              localIdentName: '[name]__[local]'
            }
          }
        },
        'less-loader'
      ]
    })

    console.log(oneOfRule.oneOf)
    // Always return the config object.
    return webpackConfig
  }
}

module.exports = {
  plugins: [
    {
      plugin: CracoAntDesignPlugin,
      options: {
        customizeTheme: {
          '@primary-color': '#1DA57A'
        }
      }
    },
    {
      plugin: lessConfig,
      options: { preText: 'Will log the craco config:' }
    }
  ],
  webpack: {
    alias: {
      '@': resolve(__dirname, 'src')
    }
  }
}

mock-api

yarn add mock-api,接下来就是配置了,在根目录下新建一个overrideDevServerConfig.js

overrideDevServerConfig.js

/* eslint-disable @typescript-eslint/no-var-requires */
const apiMocker = require('mocker-api')
const { resolve } = require('path')

module.exports = {
  overrideDevServerConfig: ({
    devServerConfig,
    cracoConfig,
    pluginOptions,
    context: { env, paths, allowedHost }
  }) => {
    if (pluginOptions.preText) {
      console.log(pluginOptions.preText)
    }

    devServerConfig.port = 3003
    devServerConfig.before = (app, server, compiler) => {
      apiMocker(app, resolve(__dirname, './mock/index.ts'))
    }

    // Always return the config object.
    return devServerConfig
  }
}

mock/index.ts

const proxy = {
  'GET /menu': {
    test: 'menu'
  }
}

module.exports = proxy

craco.config.js

const devServerConfig = require('./overrideDevServerConfig')
module.exports = {
  plugins: [
    {
      plugin: CracoAntDesignPlugin,
      options: {
        customizeTheme: {
          '@primary-color': '#1DA57A'
        }
      }
    },
    {
      plugin: devServerConfig,
      options: { preText: 'Will log the craco config:' }
    }
  ],
  webpack: {
    alias: {
      '@': resolve(__dirname, 'src')
    }
  }
}

参考链接

参考1

参考2

参考3

参考4