This is the first day of my participation in Gwen Challenge

Recently, the team was developing a component library where they encountered a problem with customizing theme colors based on the UI for use in different businesses.

How to do that?

Referring to Antd’s theme scheme, the theme color variable is passed to the modifyVars property in the lessLoader at build time to implement color control through the less variable. There’s a lot of detail here, so let’s talk about it. First of all, our project uses UMI to build, and we need to configure.umirc (of course, if you use Webpack, the same is basically the case, which is not specified below).

/ /. Umirc configuration
const theme = require('./config/share').read('myTheme')...const lessLoader = {
  modifyVars: {
    '@base-font-size': '12px',},javascriptEnabled: true,}export default{... lessLoader, ... }Copy the code

Config /share is a plugin for dealing with topic variables, including file dependencies:

const lessJs = require('less-vars-to-js') = function (fileName) {
  const { code } = loadLessWithImports(`src/themes/${fileName}.less`)
  return lessJs(code)

/* * Parse the dependent less variables in the less file and merge the output */
function loadLessWithImports(entry) {
  const input = readFileSync(entry, 'utf8')
  const importRegExp = /^@import\s+['"]([^'"]+)['"]; $/gm
  // Check if @import is introduced
  const imports = getRegexpMatches(importRegExp, input).map((match) = > {
    const importPath = match[1]
    return {
      path: importPath, ... loadLessWithImports(importPath), } })return {
    code: imports.reduceRight( // Imports arrays are merged in reverse order, otherwise the default less file variables will overwrite the custom variables
      (acc, { code }) = >
        replaceSubstring(acc, code),
    imports: imports.reduce(
      (acc, { path, imports: nestedImports }) = > [...acc, ...nestedImports, path],

/* * Get the matching less file */
function getRegexpMatches(regexp, text) {
  var matches = []
  var lastIndex = regexp.lastIndex
  var match

  do {
    match = regexp.exec(text)
    if (match) {
    } // prevent infinite loop (only regular expressions with `global` flag retain the `lastIndex`)
  } while (match && // don't leak `lastIndex` changes

  regexp.lastIndex = lastIndex

  return matches
Copy the code

The main method is loadLessWithImports, because the overall idea is relatively clear, mainly how to achieve file parsing. It takes the less file path as an argument, parses the @import dependency file through the re, and recursively calls the parsing.


Refer to the link

  • Antd’s thematic scheme