diff --git a/.antd-tools.config.js b/.antd-tools.config.js
new file mode 100644
index 000000000..7a5bec367
--- /dev/null
+++ b/.antd-tools.config.js
@@ -0,0 +1,195 @@
+const fs = require('fs');
+const path = require('path');
+const defaultVars = require('./scripts/default-vars');
+const darkVars = require('./scripts/dark-vars');
+const compactVars = require('./scripts/compact-vars');
+
+function generateThemeFileContent(theme) {
+  return `const { ${theme}ThemeSingle } = require('./theme');\nconst defaultTheme = require('./default-theme');\n
+module.exports = {
+  ...defaultTheme,
+  ...${theme}ThemeSingle
+}`;
+}
+
+// We need compile additional content for antd user
+function finalizeCompile() {
+  if (fs.existsSync(path.join(__dirname, './lib'))) {
+    // Build a entry less file to dist/antd.less
+    const componentsPath = path.join(process.cwd(), 'components');
+    let componentsLessContent = '';
+    // Build components in one file: lib/style/components.less
+    fs.readdir(componentsPath, (err, files) => {
+      files.forEach(file => {
+        if (fs.existsSync(path.join(componentsPath, file, 'style', 'index.less'))) {
+          componentsLessContent += `@import "../${path.posix.join(
+            file,
+            'style',
+            'index-pure.less',
+          )}";\n`;
+        }
+      });
+      fs.writeFileSync(
+        path.join(process.cwd(), 'lib', 'style', 'components.less'),
+        componentsLessContent,
+      );
+    });
+  }
+}
+
+function buildThemeFile(theme, vars) {
+  // Build less entry file: dist/antd.${theme}.less
+  if (theme !== 'default') {
+    fs.writeFileSync(
+      path.join(process.cwd(), 'dist', `antd.${theme}.less`),
+      `@import "../lib/style/${theme}.less";\n@import "../lib/style/components.less";`,
+    );
+    // eslint-disable-next-line no-console
+    console.log(`Built a entry less file to dist/antd.${theme}.less`);
+  } else {
+    fs.writeFileSync(
+      path.join(process.cwd(), 'dist', `default-theme.js`),
+      `module.exports = ${JSON.stringify(vars, null, 2)};\n`,
+    );
+    return;
+  }
+
+  // Build ${theme}.js: dist/${theme}-theme.js, for less-loader
+
+  fs.writeFileSync(
+    path.join(process.cwd(), 'dist', `theme.js`),
+    `const ${theme}ThemeSingle = ${JSON.stringify(vars, null, 2)};\n`,
+    {
+      flag: 'a',
+    },
+  );
+
+  fs.writeFileSync(
+    path.join(process.cwd(), 'dist', `${theme}-theme.js`),
+    generateThemeFileContent(theme),
+  );
+
+  // eslint-disable-next-line no-console
+  console.log(`Built a ${theme} theme js file to dist/${theme}-theme.js`);
+}
+
+function finalizeDist() {
+  if (fs.existsSync(path.join(__dirname, './dist'))) {
+    // Build less entry file: dist/antd.less
+    fs.writeFileSync(
+      path.join(process.cwd(), 'dist', 'antd.less'),
+      '@import "../lib/style/default.less";\n@import "../lib/style/components.less";',
+    );
+    // eslint-disable-next-line no-console
+    fs.writeFileSync(
+      path.join(process.cwd(), 'dist', 'theme.js'),
+      `const defaultTheme = require('./default-theme.js');\n`,
+    );
+    // eslint-disable-next-line no-console
+    console.log('Built a entry less file to dist/antd.less');
+    buildThemeFile('default', defaultVars);
+    buildThemeFile('dark', darkVars);
+    buildThemeFile('compact', compactVars);
+    buildThemeFile('variable', {});
+    fs.writeFileSync(
+      path.join(process.cwd(), 'dist', `theme.js`),
+      `
+function getThemeVariables(options = {}) {
+  let themeVar = {
+    'hack': \`true;@import "\${require.resolve('antd/lib/style/color/colorPalette.less')}";\`,
+    ...defaultTheme
+  };
+  if(options.dark) {
+    themeVar = {
+      ...themeVar,
+      ...darkThemeSingle
+    }
+  }
+  if(options.compact){
+    themeVar = {
+      ...themeVar,
+      ...compactThemeSingle
+    }
+  }
+  return themeVar;
+}
+
+module.exports = {
+  darkThemeSingle,
+  compactThemeSingle,
+  getThemeVariables
+}`,
+      {
+        flag: 'a',
+      },
+    );
+  }
+}
+
+function isComponentStyleEntry(file) {
+  return file.path.match(/style(\/|\\)index\.tsx/);
+}
+
+function needTransformStyle(content) {
+  return content.includes('../../style/index.less') || content.includes('./index.less');
+}
+
+module.exports = {
+  compile: {
+    includeLessFile: [/(\/|\\)components(\/|\\)style(\/|\\)default.less$/],
+    transformTSFile(file) {
+      if (isComponentStyleEntry(file)) {
+        let content = file.contents.toString();
+
+        if (needTransformStyle(content)) {
+          const cloneFile = file.clone();
+
+          // Origin
+          content = content.replace('../../style/index.less', '../../style/default.less');
+          cloneFile.contents = Buffer.from(content);
+
+          return cloneFile;
+        }
+      }
+    },
+    transformFile(file) {
+      if (isComponentStyleEntry(file)) {
+        const indexLessFilePath = file.path.replace('index.tsx', 'index.less');
+
+        if (fs.existsSync(indexLessFilePath)) {
+          // We put origin `index.less` file to `index-pure.less`
+          const pureFile = file.clone();
+          pureFile.contents = Buffer.from(fs.readFileSync(indexLessFilePath, 'utf8'));
+          pureFile.path = pureFile.path.replace('index.tsx', 'index-pure.less');
+
+          // Rewrite `index.less` file with `root-entry-name`
+          const indexLessFile = file.clone();
+          indexLessFile.contents = Buffer.from(
+            [
+              // Inject variable
+              '@root-entry-name: default;',
+              // Point to origin file
+              "@import './index-pure.less';",
+            ].join('\n\n'),
+          );
+          indexLessFile.path = indexLessFile.path.replace('index.tsx', 'index.less');
+
+          return [indexLessFile, pureFile];
+        }
+      }
+
+      return [];
+    },
+    lessConfig: {
+      modifyVars: {
+        'root-entry-name': 'default',
+      },
+    },
+    finalize: finalizeCompile,
+  },
+  dist: {
+    finalize: finalizeDist,
+  },
+  generateThemeFileContent,
+  bail: true,
+};
diff --git a/.gitignore b/.gitignore
index 528ba0b75..a34900353 100644
--- a/.gitignore
+++ b/.gitignore
@@ -76,3 +76,5 @@ vetur/
 report.html
 
 site/src/router/demoRoutes.js
+
+components/version/version.tsx
diff --git a/antd-tools/apiCollection.js b/antd-tools/apiCollection.js
new file mode 100644
index 000000000..99843601c
--- /dev/null
+++ b/antd-tools/apiCollection.js
@@ -0,0 +1,68 @@
+// Read all the api from current documents
+
+const glob = require('glob');
+const fs = require('fs');
+
+const COMPONENT_NAME = /components\/([^/]*)/;
+const PROP_NAME = /^\s*\|\s*([^\s|]*)/;
+
+const components = {};
+
+function mappingPropLine(component, line) {
+  const propMatch = line.match(PROP_NAME);
+  if (!propMatch) return;
+
+  const propName = propMatch[1];
+  if (!/^[a-z]/.test(propName)) return;
+
+  components[component] = Array.from(new Set([...(components[component] || []), propName]));
+}
+
+function apiReport(entities) {
+  const apis = {};
+  Object.keys(entities).forEach(component => {
+    const apiList = entities[component];
+    apiList.forEach(api => {
+      if (typeof apis[api] === 'function') {
+        apis[api] = [];
+      }
+      apis[api] = [...(apis[api] || []), component];
+    });
+  });
+
+  return apis;
+}
+
+function printReport(apis) {
+  const apiList = Object.keys(apis).map(api => ({
+    name: api,
+    componentList: apis[api],
+  }));
+  apiList.sort((a, b) => b.componentList.length - a.componentList.length);
+  // eslint-disable-next-line no-console
+  console.log('| name | components | comments |');
+  // eslint-disable-next-line no-console
+  console.log('| ---- | ---------- | -------- |');
+  apiList.forEach(({ name, componentList }) => {
+    // eslint-disable-next-line no-console
+    console.log('|', name, '|', componentList.join(', '), '| |');
+  });
+}
+
+module.exports = () => {
+  glob('components/*/*.md', (error, files) => {
+    files.forEach(filePath => {
+      // Read md file to parse content
+      const content = fs.readFileSync(filePath, 'utf8');
+      const component = filePath.match(COMPONENT_NAME)[1];
+
+      // Parse lines to get API
+      const lines = content.split(/[\r\n]+/);
+      lines.forEach(line => {
+        mappingPropLine(component, line);
+      });
+    });
+
+    printReport(apiReport(components));
+  });
+};
diff --git a/antd-tools/cli/run.js b/antd-tools/cli/run.js
index b60b54bb0..e1466aa6c 100644
--- a/antd-tools/cli/run.js
+++ b/antd-tools/cli/run.js
@@ -4,7 +4,6 @@
 'use strict';
 
 require('colorful').colorful();
-require('colorful').isatty = true;
 const gulp = require('gulp');
 const program = require('commander');
 
diff --git a/antd-tools/getNpm.js b/antd-tools/getNpm.js
new file mode 100644
index 000000000..52eee5011
--- /dev/null
+++ b/antd-tools/getNpm.js
@@ -0,0 +1,17 @@
+'use strict';
+
+const runCmd = require('./runCmd');
+
+module.exports = function (done) {
+  if (process.env.NPM_CLI) {
+    done(process.env.NPM_CLI);
+    return;
+  }
+  runCmd('which', ['tnpm'], code => {
+    let npm = 'npm';
+    if (!code) {
+      npm = 'tnpm';
+    }
+    done(npm);
+  });
+};
diff --git a/antd-tools/gulpfile.js b/antd-tools/gulpfile.js
index 6a3243cec..9090cfab8 100644
--- a/antd-tools/gulpfile.js
+++ b/antd-tools/gulpfile.js
@@ -1,5 +1,5 @@
 /* eslint-disable no-console */
-const { getProjectPath } = require('./utils/projectHelper');
+const { getProjectPath, getConfig } = require('./utils/projectHelper');
 const runCmd = require('./runCmd');
 const getBabelCommonConfig = require('./getBabelCommonConfig');
 const merge2 = require('merge2');
@@ -26,6 +26,7 @@ const stripCode = require('gulp-strip-code');
 const compareVersions = require('compare-versions');
 const getTSCommonConfig = require('./getTSCommonConfig');
 const replaceLib = require('./replaceLib');
+const sortApiTable = require('./sortApiTable');
 
 const packageJson = require(getProjectPath('package.json'));
 const tsDefaultReporter = ts.reporter.defaultReporter();
@@ -49,11 +50,17 @@ function dist(done) {
     }
 
     const info = stats.toJson();
+    const { dist: { finalize } = {}, bail } = getConfig();
 
     if (stats.hasErrors()) {
-      console.error(info.errors);
+      (info.errors || []).forEach(error => {
+        console.error(error);
+      });
+      // https://github.com/ant-design/ant-design/pull/31662
+      if (bail) {
+        process.exit(1);
+      }
     }
-
     if (stats.hasWarnings()) {
       console.warn(info.warnings);
     }
@@ -68,6 +75,11 @@ function dist(done) {
       version: false,
     });
     console.log(buildInfo);
+    // Additional process of dist finalize
+    if (finalize) {
+      console.log('[Dist] Finalization...');
+      finalize();
+    }
     done(0);
   });
 }
@@ -103,7 +115,7 @@ function babelify(js, modules) {
   if (modules === false) {
     babelConfig.plugins.push(replaceLib);
   }
-  let stream = js.pipe(babel(babelConfig)).pipe(
+  const stream = js.pipe(babel(babelConfig)).pipe(
     through2.obj(function z(file, encoding, next) {
       this.push(file.clone());
       if (file.path.match(/\/style\/index\.(js|jsx|ts|tsx)$/)) {
@@ -128,33 +140,40 @@ function babelify(js, modules) {
       next();
     }),
   );
-  if (modules === false) {
-    stream = stream.pipe(
-      stripCode({
-        start_comment: '@remove-on-es-build-begin',
-        end_comment: '@remove-on-es-build-end',
-      }),
-    );
-  }
   return stream.pipe(gulp.dest(modules === false ? esDir : libDir));
 }
 
 function compile(modules) {
+  const { compile: { transformTSFile, transformFile, includeLessFile = [] } = {} } = getConfig();
   rimraf.sync(modules !== false ? libDir : esDir);
+
+  // =============================== LESS ===============================
   const less = gulp
     .src(['components/**/*.less'])
     .pipe(
       through2.obj(function (file, encoding, next) {
-        this.push(file.clone());
+        // Replace content
+        const cloneFile = file.clone();
+        const content = file.contents.toString().replace(/^\uFEFF/, '');
+
+        cloneFile.contents = Buffer.from(content);
+
+        // Clone for css here since `this.push` will modify file.path
+        const cloneCssFile = cloneFile.clone();
+
+        this.push(cloneFile);
+
+        // Transform less file
         if (
-          file.path.match(/\/style\/index\.less$/) ||
-          file.path.match(/\/style\/v2-compatible-reset\.less$/)
+          file.path.match(/(\/|\\)style(\/|\\)index\.less$/) ||
+          file.path.match(/(\/|\\)style(\/|\\)v2-compatible-reset\.less$/) ||
+          includeLessFile.some(regex => file.path.match(regex))
         ) {
-          transformLess(file.path)
+          transformLess(cloneCssFile.contents.toString(), cloneCssFile.path)
             .then(css => {
-              file.contents = Buffer.from(css);
-              file.path = file.path.replace(/\.less$/, '.css');
-              this.push(file);
+              cloneCssFile.contents = Buffer.from(css);
+              cloneCssFile.path = cloneCssFile.path.replace(/\.less$/, '.css');
+              this.push(cloneCssFile);
               next();
             })
             .catch(e => {
@@ -170,6 +189,25 @@ function compile(modules) {
     .src(['components/**/*.@(png|svg)'])
     .pipe(gulp.dest(modules === false ? esDir : libDir));
   let error = 0;
+
+  // =============================== FILE ===============================
+  let transformFileStream;
+
+  if (transformFile) {
+    transformFileStream = gulp
+      .src(['components/**/*.tsx'])
+      .pipe(
+        through2.obj(function (file, encoding, next) {
+          let nextFile = transformFile(file) || file;
+          nextFile = Array.isArray(nextFile) ? nextFile : [nextFile];
+          nextFile.forEach(f => this.push(f));
+          next();
+        }),
+      )
+      .pipe(gulp.dest(modules === false ? esDir : libDir));
+  }
+
+  // ================================ TS ================================
   const source = [
     'components/**/*.js',
     'components/**/*.jsx',
@@ -179,7 +217,29 @@ function compile(modules) {
     '!components/*/__tests__/*',
   ];
 
-  const tsResult = gulp.src(source).pipe(
+  // Strip content if needed
+  let sourceStream = gulp.src(source);
+  if (modules === false) {
+    sourceStream = sourceStream.pipe(
+      stripCode({
+        start_comment: '@remove-on-es-build-begin',
+        end_comment: '@remove-on-es-build-end',
+      }),
+    );
+  }
+
+  if (transformTSFile) {
+    sourceStream = sourceStream.pipe(
+      through2.obj(function (file, encoding, next) {
+        let nextFile = transformTSFile(file) || file;
+        nextFile = Array.isArray(nextFile) ? nextFile : [nextFile];
+        nextFile.forEach(f => this.push(f));
+        next();
+      }),
+    );
+  }
+
+  const tsResult = sourceStream.pipe(
     ts(tsConfig, {
       error(e) {
         tsDefaultReporter.error(e);
@@ -199,7 +259,7 @@ function compile(modules) {
   tsResult.on('end', check);
   const tsFilesStream = babelify(tsResult.js, modules);
   const tsd = tsResult.dts.pipe(gulp.dest(modules === false ? esDir : libDir));
-  return merge2([less, tsFilesStream, tsd, assets]);
+  return merge2([less, tsFilesStream, tsd, assets, transformFileStream].filter(s => s));
 }
 
 function tag() {
@@ -420,7 +480,11 @@ gulp.task(
     const npmArgs = getNpmArgs();
     if (npmArgs) {
       for (let arg = npmArgs.shift(); arg; arg = npmArgs.shift()) {
-        if (/^pu(b(l(i(sh?)?)?)?)?$/.test(arg) && npmArgs.indexOf('--with-antd-tools') < 0) {
+        if (
+          /^pu(b(l(i(sh?)?)?)?)?$/.test(arg) &&
+          npmArgs.indexOf('--with-antd-tools') < 0 &&
+          !process.env.npm_config_with_antd_tools
+        ) {
           reportError();
           done(1);
           return;
@@ -430,3 +494,11 @@ gulp.task(
     done();
   }),
 );
+
+gulp.task(
+  'sort-api-table',
+  gulp.series(done => {
+    sortApiTable();
+    done();
+  }),
+);
diff --git a/antd-tools/replaceLib.js b/antd-tools/replaceLib.js
index 08d84b4ea..e9da6e86c 100644
--- a/antd-tools/replaceLib.js
+++ b/antd-tools/replaceLib.js
@@ -12,6 +12,19 @@ function replacePath(path) {
       path.node.source.value = esModule;
     }
   }
+
+  // @ant-design/icons-vue/xxx => @ant-design/icons-vue/es/icons/xxx
+  const antdIconMatcher = /@ant-design\/icons-vue\/([^/]*)$/;
+  if (path.node.source && antdIconMatcher.test(path.node.source.value)) {
+    const esModule = path.node.source.value.replace(
+      antdIconMatcher,
+      (_, iconName) => `@ant-design/icons-vue/es/icons/${iconName}`,
+    );
+    const esPath = dirname(getProjectPath('node_modules', esModule));
+    if (fs.existsSync(esPath)) {
+      path.node.source.value = esModule;
+    }
+  }
 }
 
 function replaceLib() {
diff --git a/antd-tools/runCmd.js b/antd-tools/runCmd.js
index f5a822a97..b25ca5711 100644
--- a/antd-tools/runCmd.js
+++ b/antd-tools/runCmd.js
@@ -1,9 +1,17 @@
 'use strict';
 
+const isWindows = require('is-windows');
 const getRunCmdEnv = require('./utils/getRunCmdEnv');
 
 function runCmd(cmd, _args, fn) {
   const args = _args || [];
+
+  if (isWindows()) {
+    args.unshift(cmd);
+    args.unshift('/c');
+    cmd = process.env.ComSpec;
+  }
+
   const runner = require('child_process').spawn(cmd, args, {
     // keep color
     stdio: 'inherit',
diff --git a/antd-tools/sortApiTable.js b/antd-tools/sortApiTable.js
new file mode 100644
index 000000000..56a2bd21b
--- /dev/null
+++ b/antd-tools/sortApiTable.js
@@ -0,0 +1,165 @@
+const program = require('commander');
+const majo = require('majo');
+const fs = require('fs');
+const path = require('path');
+const chalk = require('chalk');
+
+const unified = require('unified');
+const parse = require('remark-parse');
+const stringify = require('remark-stringify');
+
+const yamlConfig = require('remark-yaml-config');
+const frontmatter = require('remark-frontmatter');
+
+let fileAPIs = {};
+const remarkWithYaml = unified()
+  .use(parse)
+  .use(stringify, {
+    paddedTable: false,
+    listItemIndent: 1,
+    stringLength: () => 3,
+  })
+  .use(frontmatter)
+  .use(yamlConfig);
+
+const stream = majo.majo();
+
+function getCellValue(node) {
+  return node.children[0].children[0].value;
+}
+
+// from small to large
+const sizeBreakPoints = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'];
+
+const whiteMethodList = ['afterChange', 'beforeChange'];
+
+const groups = {
+  isDynamic: val => /^on[A-Z]/.test(val) || whiteMethodList.indexOf(val) > -1,
+  isSize: val => sizeBreakPoints.indexOf(val) > -1,
+};
+
+function asciiSort(prev, next) {
+  if (prev > next) {
+    return 1;
+  }
+
+  if (prev < next) {
+    return -1;
+  }
+
+  return 0;
+}
+
+// follow the alphabet order
+function alphabetSort(nodes) {
+  // use toLowerCase to keep `case insensitive`
+  return nodes.sort((...comparison) =>
+    asciiSort(...comparison.map(val => getCellValue(val).toLowerCase())),
+  );
+}
+
+function sizeSort(nodes) {
+  return nodes.sort((...comparison) =>
+    asciiSort(...comparison.map(val => sizeBreakPoints.indexOf(getCellValue(val).toLowerCase()))),
+  );
+}
+
+function sort(ast, filename) {
+  const nameMatch = filename.match(/^components\/([^/]*)\//);
+  const componentName = nameMatch[1];
+  fileAPIs[componentName] = fileAPIs[componentName] || {
+    static: new Set(),
+    size: new Set(),
+    dynamic: new Set(),
+  };
+
+  ast.children.forEach(child => {
+    const staticProps = [];
+    // prefix with `on`
+    const dynamicProps = [];
+    // one of ['xs', 'sm', 'md', 'lg', 'xl']
+    const sizeProps = [];
+
+    // find table markdown type
+    if (child.type === 'table') {
+      // slice will create new array, so sort can affect the original array.
+      // slice(1) cut down the thead
+      child.children.slice(1).forEach(node => {
+        const value = getCellValue(node);
+        if (groups.isDynamic(value)) {
+          dynamicProps.push(node);
+          fileAPIs[componentName].dynamic.add(value);
+        } else if (groups.isSize(value)) {
+          sizeProps.push(node);
+          fileAPIs[componentName].size.add(value);
+        } else {
+          staticProps.push(node);
+          fileAPIs[componentName].static.add(value);
+        }
+      });
+
+      // eslint-disable-next-line
+      child.children = [
+        child.children[0],
+        ...alphabetSort(staticProps),
+        ...sizeSort(sizeProps),
+        ...alphabetSort(dynamicProps),
+      ];
+    }
+  });
+
+  return ast;
+}
+
+function sortAPI(md, filename) {
+  return remarkWithYaml.stringify(sort(remarkWithYaml.parse(md), filename));
+}
+
+function sortMiddleware(ctx) {
+  Object.keys(ctx.files).forEach(filename => {
+    const content = ctx.fileContents(filename);
+    ctx.writeContents(filename, sortAPI(content, filename));
+  });
+}
+
+module.exports = () => {
+  fileAPIs = {};
+
+  program
+    .version('0.1.0')
+    .option(
+      '-f, --file [file]',
+      'Specify which file to be transformed',
+      // default value
+      'components/**/index.+(zh-CN|en-US).md',
+    )
+    .option('-o, --output [output]', 'Specify component api output path', '~component-api.json')
+    .parse(process.argv);
+  // Get the markdown file all need to be transformed
+
+  /* eslint-disable no-console */
+  stream
+    .source(program.file)
+    .use(sortMiddleware)
+    .dest('.')
+    .then(() => {
+      if (program.output) {
+        const data = {};
+        Object.keys(fileAPIs).forEach(componentName => {
+          data[componentName] = {
+            static: [...fileAPIs[componentName].static],
+            size: [...fileAPIs[componentName].size],
+            dynamic: [...fileAPIs[componentName].dynamic],
+          };
+        });
+
+        const reportPath = path.resolve(program.output);
+        fs.writeFileSync(reportPath, JSON.stringify(data, null, 2), 'utf8');
+        console.log(chalk.cyan(`API list file: ${reportPath}`));
+      }
+    })
+    .then(() => {
+      console.log(chalk.green(`sort ant-design-vue api successfully!`));
+    });
+  /* eslint-enable no-console */
+};
diff --git a/antd-tools/transformLess.js b/antd-tools/transformLess.js
index 370ffc17b..0e949b243 100644
--- a/antd-tools/transformLess.js
+++ b/antd-tools/transformLess.js
@@ -1,16 +1,14 @@
 const less = require('less');
-const { readFileSync } = require('fs');
 const path = require('path');
 const postcss = require('postcss');
-const NpmImportPlugin = require('less-plugin-npm-import');
 const autoprefixer = require('autoprefixer');
+const NpmImportPlugin = require('less-plugin-npm-import');
+const { getConfig } = require('./utils/projectHelper');
 
-function transformLess(lessFile, config = {}) {
+function transformLess(lessContent, lessFilePath, config = {}) {
   const { cwd = process.cwd() } = config;
-  const resolvedLessFile = path.resolve(cwd, lessFile);
-
-  let data = readFileSync(resolvedLessFile, 'utf-8');
-  data = data.replace(/^\uFEFF/, '');
+  const { compile: { lessConfig } = {} } = getConfig();
+  const resolvedLessFile = path.resolve(cwd, lessFilePath);
 
   // Do less compile
   const lessOpts = {
@@ -18,13 +16,12 @@ function transformLess(lessFile, config = {}) {
     filename: resolvedLessFile,
     plugins: [new NpmImportPlugin({ prefix: '~' })],
     javascriptEnabled: true,
+    ...lessConfig,
   };
   return less
-    .render(data, lessOpts)
+    .render(lessContent, lessOpts)
     .then(result => postcss([autoprefixer]).process(result.css, { from: undefined }))
-    .then(r => {
-      return r.css;
-    });
+    .then(r => r.css);
 }
 
 module.exports = transformLess;
diff --git a/antd-tools/utils/CleanUpStatsPlugin.js b/antd-tools/utils/CleanUpStatsPlugin.js
index 5029bba39..300168c4f 100644
--- a/antd-tools/utils/CleanUpStatsPlugin.js
+++ b/antd-tools/utils/CleanUpStatsPlugin.js
@@ -24,13 +24,13 @@ class CleanUpStatsPlugin {
 
   apply(compiler) {
     compiler.hooks.done.tap('CleanUpStatsPlugin', stats => {
-      const { children } = stats.compilation;
+      const { children, warnings } = stats.compilation;
       if (Array.isArray(children)) {
         stats.compilation.children = children.filter(child => this.shouldPickStatChild(child));
       }
-      // if (Array.isArray(warnings)) {
-      //   stats.compilation.warnings = warnings.filter(message => this.shouldPickWarning(message));
-      // }
+      if (Array.isArray(warnings)) {
+        stats.compilation.warnings = warnings.filter(message => this.shouldPickWarning(message));
+      }
     });
   }
 }
diff --git a/antd-tools/utils/get-npm-args.js b/antd-tools/utils/get-npm-args.js
index 9de9013c1..2e11613cc 100644
--- a/antd-tools/utils/get-npm-args.js
+++ b/antd-tools/utils/get-npm-args.js
@@ -2,6 +2,11 @@
 
 // NOTE: the following code was partially adopted from https://github.com/iarna/in-publish
 module.exports = function getNpmArgs() {
+  // https://github.com/iarna/in-publish/pull/14
+  if (process.env.npm_command) {
+    return [process.env.npm_command];
+  }
+
   let npmArgv = null;
 
   try {
diff --git a/antd-tools/utils/getRunCmdEnv.js b/antd-tools/utils/getRunCmdEnv.js
index c7b474bb3..12e326050 100644
--- a/antd-tools/utils/getRunCmdEnv.js
+++ b/antd-tools/utils/getRunCmdEnv.js
@@ -1,6 +1,7 @@
 'use strict';
 
 const path = require('path');
+const isWindows = require('is-windows');
 
 module.exports = function getRunCmdEnv() {
   const env = {};
@@ -14,7 +15,9 @@ module.exports = function getRunCmdEnv() {
     .filter(v => v.slice(0, 1).pop().toLowerCase() === 'path')
     .forEach(v => {
       const key = v.slice(0, 1).pop();
-      env[key] = env[key] ? `${nodeModulesBinDir}:${env[key]}` : nodeModulesBinDir;
+      env[key] = env[key]
+        ? `${nodeModulesBinDir}${isWindows() ? ';' : ':'}${env[key]}`
+        : nodeModulesBinDir;
     });
   return env;
 };
diff --git a/antd-tools/utils/projectHelper.js b/antd-tools/utils/projectHelper.js
index 79cdb57cc..9ade6c777 100644
--- a/antd-tools/utils/projectHelper.js
+++ b/antd-tools/utils/projectHelper.js
@@ -13,6 +13,7 @@ function resolve(moduleName) {
 
 // We need hack the require to ensure use package module first
 // For example, `typescript` is required by `gulp-typescript` but provided by `antd`
+// we do not need for ant-design-vue
 let injected = false;
 function injectRequire() {
   if (injected) return;
@@ -45,9 +46,35 @@ function getConfig() {
   return {};
 }
 
+/**
+ * 是否存在可用的browserslist config
+ * https://github.com/browserslist/browserslist#queries
+ * @returns
+ */
+function isThereHaveBrowserslistConfig() {
+  try {
+    const packageJson = require(getProjectPath('package.json'));
+    if (packageJson.browserslist) {
+      return true;
+    }
+  } catch (e) {
+    //
+  }
+  if (fs.existsSync(getProjectPath('.browserslistrc'))) {
+    return true;
+  }
+  if (fs.existsSync(getProjectPath('browserslist'))) {
+    return true;
+  }
+  // parent项目的配置支持,需要再补充
+  // ROWSERSLIST ROWSERSLIST_ENV 变量的形式,需要再补充。
+  return false;
+}
+
 module.exports = {
   getProjectPath,
   resolve,
   injectRequire,
   getConfig,
+  isThereHaveBrowserslistConfig,
 };
diff --git a/antd-tools/utils/styleUtil.js b/antd-tools/utils/styleUtil.js
new file mode 100644
index 000000000..7b05ee315
--- /dev/null
+++ b/antd-tools/utils/styleUtil.js
@@ -0,0 +1,11 @@
+// We convert less import in es/lib to css file path
+function cssInjection(content) {
+  return content
+    .replace(/\/style\/?'/g, "/style/css'")
+    .replace(/\/style\/?"/g, '/style/css"')
+    .replace(/\.less/g, '.css');
+}
+
+module.exports = {
+  cssInjection,
+};
diff --git a/components/version/index.ts b/components/version/index.ts
index 882678218..36bbb7bee 100644
--- a/components/version/index.ts
+++ b/components/version/index.ts
@@ -1,5 +1,5 @@
-import pkg from '../../package.json';
-
-const { version } = pkg;
+/* eslint import/no-unresolved: 0 */
+// @ts-ignore
+import version from './version';
 
 export default version;
diff --git a/package.json b/package.json
index f4f004cd2..4fd345d35 100644
--- a/package.json
+++ b/package.json
@@ -30,14 +30,14 @@
   ],
   "scripts": {
     "predev": "node node_modules/esbuild/install.js",
-    "dev": "yarn predev && yarn routes && vite serve site",
+    "dev": "npm run version && yarn predev && yarn routes && vite serve site",
     "test": "cross-env NODE_ENV=test jest --config .jest.js",
     "compile": "node antd-tools/cli/run.js compile",
     "generator-webtypes": "tsc -p antd-tools/generator-types/tsconfig.json && node antd-tools/generator-types/index.js",
-    "pub": "node --max_old_space_size=8192 antd-tools/cli/run.js pub",
-    "pub-with-ci": "node antd-tools/cli/run.js pub-with-ci",
+    "pub": "npm run version && node --max_old_space_size=8192 antd-tools/cli/run.js pub",
+    "pub-with-ci": "npm run version && node antd-tools/cli/run.js pub-with-ci",
     "prepublishOnly": "node antd-tools/cli/run.js guard",
-    "pre-publish": "node ./scripts/prepub && npm run generator-webtypes",
+    "pre-publish": "npm run generator-webtypes",
     "prettier": "prettier -c --write **/*",
     "pretty-quick": "pretty-quick",
     "dist": "node --max_old_space_size=8192 antd-tools/cli/run.js dist",
@@ -54,8 +54,17 @@
     "vue-tsc": "vue-tsc --noEmit",
     "site": "yarn routes && ./node_modules/vite/bin/vite.js build site --base=https://next.antdv.com/",
     "pub:site": "npm run site && node site/scripts/pushToOSS.js",
-    "prepare": "husky install"
+    "prepare": "husky install",
+    "version": "node ./scripts/generate-version",
+    "sort-api": "node antd-tools/cli/run.js sort-api-table"
   },
+  "browserslist": [
+    "> 0.5%",
+    "last 2 versions",
+    "Firefox ESR",
+    "not dead",
+    "not IE 11"
+  ],
   "repository": {
     "type": "git",
     "url": "git+https://github.com/vueComponent/ant-design-vue.git"
@@ -162,6 +171,7 @@
     "html-webpack-plugin": "^5.3.1",
     "husky": "^6.0.0",
     "ignore-emit-webpack-plugin": "^2.0.6",
+    "is-windows": "^1.0.2",
     "jest": "^26.0.0",
     "jest-environment-jsdom-fifteen": "^1.0.2",
     "jest-serializer-vue": "^2.0.0",
@@ -174,6 +184,7 @@
     "less-plugin-npm-import": "^2.1.0",
     "less-vars-to-js": "^1.3.0",
     "lint-staged": "^11.0.0",
+    "majo": "^0.10.1",
     "markdown-it": "^8.4.2",
     "markdown-it-anchor": "^8.0.4",
     "markdown-it-container": "^3.0.0",
@@ -197,6 +208,10 @@
     "query-string": "^7.0.1",
     "querystring": "^0.2.0",
     "raw-loader": "^4.0.2",
+    "remark-frontmatter": "^2.0.0",
+    "remark-parse": "^8.0.0",
+    "remark-stringify": "^8.0.0",
+    "remark-yaml-config": "^4.1.0",
     "reqwest": "^2.0.5",
     "rimraf": "^3.0.0",
     "rucksack-css": "^1.0.2",
diff --git a/scripts/css-variable-sync.js b/scripts/css-variable-sync.js
new file mode 100644
index 000000000..f46cb13c1
--- /dev/null
+++ b/scripts/css-variable-sync.js
@@ -0,0 +1,222 @@
+/**
+ * ZombieJ: Since we still need mainly maintain the `default.less`. Create a script that generate
+ * `variable.less` from the `default.less`
+ */
+
+const fse = require('fs-extra');
+const path = require('path');
+const chalk = require('chalk');
+
+const folderPath = path.resolve(__dirname, '..', 'components', 'style', 'themes');
+const targetPath = path.resolve(folderPath, 'variable.less');
+
+const defaultContent = fse.readFileSync(path.resolve(folderPath, 'default.less'), 'utf8');
+
+// const variableContent = fse.readFileSync(
+//   path.resolve(__dirname, '..', 'components', 'style', 'themes', 'variable.less'),
+//   'utf8',
+// );
+
+let variableContent = defaultContent;
+
+function replaceVariable(key, value) {
+  variableContent = variableContent.replace(new RegExp(`@${key}:[^;]*;`), `@${key}: ${value};`);
+}
+
+function replaceVariableContent(key, content) {
+  const lines = variableContent.split(/\n/);
+  const startIndex = lines.findIndex(line => line.includes(`[CSS-VARIABLE-REPLACE-BEGIN: ${key}]`));
+  const endIndex = lines.findIndex(line => line.includes(`[CSS-VARIABLE-REPLACE-END: ${key}]`));
+
+  if (startIndex !== -1 && endIndex !== -1) {
+    variableContent = [...lines.slice(0, startIndex), content, ...lines.slice(endIndex + 1)].join(
+      '\n',
+    );
+  }
+}
+
+replaceVariable('theme', 'variable');
+
+replaceVariableContent(
+  'html-variables',
+  `
+html {
+  @base-primary: @blue-6;
+
+  // ========= Primary Color =========
+  --@{ant-prefix}-primary-color: @base-primary;
+  --@{ant-prefix}-primary-color-hover: color(~\`colorPalette('@{base-primary}', 5) \`);
+  --@{ant-prefix}-primary-color-active: color(~\`colorPalette('@{base-primary}', 7) \`);
+  --@{ant-prefix}-primary-color-outline: fade(@base-primary, @outline-fade);
+
+  // Legacy
+  @legacy-primary-1: color(~\`colorPalette('@{base-primary}', 1) \`);
+
+  --@{ant-prefix}-primary-1: @legacy-primary-1;
+  --@{ant-prefix}-primary-2: color(~\`colorPalette('@{base-primary}', 2) \`);
+  --@{ant-prefix}-primary-3: color(~\`colorPalette('@{base-primary}', 3) \`);
+  --@{ant-prefix}-primary-4: color(~\`colorPalette('@{base-primary}', 4) \`);
+  --@{ant-prefix}-primary-5: color(~\`colorPalette('@{base-primary}', 5) \`);
+  --@{ant-prefix}-primary-6: @base-primary;
+  --@{ant-prefix}-primary-7: color(~\`colorPalette('@{base-primary}', 7) \`);
+
+  // Deprecated
+  --@{ant-prefix}-primary-color-deprecated-pure: ~'';
+  --@{ant-prefix}-primary-color-deprecated-l-35: lighten(@base-primary, 35%);
+  --@{ant-prefix}-primary-color-deprecated-l-20: lighten(@base-primary, 20%);
+  --@{ant-prefix}-primary-color-deprecated-t-20: tint(@base-primary, 20%);
+  --@{ant-prefix}-primary-color-deprecated-t-50: tint(@base-primary, 50%);
+  --@{ant-prefix}-primary-color-deprecated-f-12: fade(@base-primary, 12%);
+  --@{ant-prefix}-primary-color-active-deprecated-f-30: fade(@legacy-primary-1, 30%);
+  --@{ant-prefix}-primary-color-active-deprecated-d-02: darken(@legacy-primary-1, 2%);
+
+  // ========= Success Color =========
+  --@{ant-prefix}-success-color: @green-6;
+  --@{ant-prefix}-success-color-hover: color(~\`colorPalette('@{green-6}', 5) \`);
+  --@{ant-prefix}-success-color-active: color(~\`colorPalette('@{green-6}', 7) \`);
+  --@{ant-prefix}-success-color-outline: fade(@green-6, @outline-fade);
+  --@{ant-prefix}-success-color-deprecated-bg: ~\`colorPalette('@{green-6}', 1) \`;
+  --@{ant-prefix}-success-color-deprecated-border: ~\`colorPalette('@{green-6}', 3) \`;
+
+  // ========== Error Color ==========
+  --@{ant-prefix}-error-color: @red-5;
+  --@{ant-prefix}-error-color-hover: color(~\`colorPalette('@{red-5}', 5) \`);
+  --@{ant-prefix}-error-color-active: color(~\`colorPalette('@{red-5}', 7) \`);
+  --@{ant-prefix}-error-color-outline: fade(@red-5, @outline-fade);
+  --@{ant-prefix}-error-color-deprecated-bg: ~\`colorPalette('@{red-5}', 1) \`;
+  --@{ant-prefix}-error-color-deprecated-border: ~\`colorPalette('@{red-5}', 3) \`;
+
+  // ========= Warning Color =========
+  --@{ant-prefix}-warning-color: @gold-6;
+  --@{ant-prefix}-warning-color-hover: color(~\`colorPalette('@{gold-6}', 5) \`);
+  --@{ant-prefix}-warning-color-active: color(~\`colorPalette('@{gold-6}', 7) \`);
+  --@{ant-prefix}-warning-color-outline: fade(@gold-6, @outline-fade);
+  --@{ant-prefix}-warning-color-deprecated-bg: ~\`colorPalette('@{gold-6}', 1) \`;
+  --@{ant-prefix}-warning-color-deprecated-border: ~\`colorPalette('@{gold-6}', 3) \`;
+
+  // ========== Info Color ===========
+  --@{ant-prefix}-info-color: @base-primary;
+  --@{ant-prefix}-info-color-deprecated-bg: ~\`colorPalette('@{base-primary}', 1) \`;
+  --@{ant-prefix}-info-color-deprecated-border: ~\`colorPalette('@{base-primary}', 3) \`;
+}
+`.trim(),
+);
+
+// >>> Primary
+replaceVariable('primary-color', "~'var(--@{ant-prefix}-primary-color)'");
+replaceVariable('primary-color-hover', "~'var(--@{ant-prefix}-primary-color-hover)'");
+replaceVariable('primary-color-active', "~'var(--@{ant-prefix}-primary-color-active)'");
+replaceVariable('primary-color-outline', "~'var(--@{ant-prefix}-primary-color-outline)'");
+
+replaceVariable('processing-color', '@primary-color');
+
+// >>> Info
+replaceVariable('info-color', "~'var(--@{ant-prefix}-info-color)'");
+replaceVariable('info-color-deprecated-bg', "~'var(--@{ant-prefix}-info-color-deprecated-bg)'");
+replaceVariable(
+  'info-color-deprecated-border',
+  "~'var(--@{ant-prefix}-info-color-deprecated-border)'",
+);
+
+// >>> Success
+replaceVariable('success-color', "~'var(--@{ant-prefix}-success-color)'");
+replaceVariable('success-color-hover', "~'var(--@{ant-prefix}-success-color-hover)'");
+replaceVariable('success-color-active', "~'var(--@{ant-prefix}-success-color-active)'");
+replaceVariable('success-color-outline', "~'var(--@{ant-prefix}-success-color-outline)'");
+replaceVariable(
+  'success-color-deprecated-bg',
+  "~'var(--@{ant-prefix}-success-color-deprecated-bg)'",
+);
+replaceVariable(
+  'success-color-deprecated-border',
+  "~'var(--@{ant-prefix}-success-color-deprecated-border)'",
+);
+
+// >>> Warning
+replaceVariable('warning-color', "~'var(--@{ant-prefix}-warning-color)'");
+replaceVariable('warning-color-hover', "~'var(--@{ant-prefix}-warning-color-hover)'");
+replaceVariable('warning-color-active', "~'var(--@{ant-prefix}-warning-color-active)'");
+replaceVariable('warning-color-outline', "~'var(--@{ant-prefix}-warning-color-outline)'");
+replaceVariable(
+  'warning-color-deprecated-bg',
+  "~'var(--@{ant-prefix}-warning-color-deprecated-bg)'",
+);
+replaceVariable(
+  'warning-color-deprecated-border',
+  "~'var(--@{ant-prefix}-warning-color-deprecated-border)'",
+);
+
+// >>> Error
+replaceVariable('error-color', "~'var(--@{ant-prefix}-error-color)'");
+replaceVariable('error-color-hover', "~'var(--@{ant-prefix}-error-color-hover)'");
+replaceVariable('error-color-active', "~'var(--@{ant-prefix}-error-color-active)'");
+replaceVariable('error-color-outline', "~'var(--@{ant-prefix}-error-color-outline)'");
+replaceVariable('error-color-deprecated-bg', "~'var(--@{ant-prefix}-error-color-deprecated-bg)'");
+replaceVariable(
+  'error-color-deprecated-border',
+  "~'var(--@{ant-prefix}-error-color-deprecated-border)'",
+);
+
+// >>> Primary Level Color
+replaceVariable('primary-1', "~'var(--@{ant-prefix}-primary-1)'");
+replaceVariable('primary-2', "~'var(--@{ant-prefix}-primary-2)'");
+replaceVariable('primary-3', "~'var(--@{ant-prefix}-primary-3)'");
+replaceVariable('primary-4', "~'var(--@{ant-prefix}-primary-4)'");
+replaceVariable('primary-5', "~'var(--@{ant-prefix}-primary-5)'");
+replaceVariable('primary-6', "~'var(--@{ant-prefix}-primary-6)'");
+replaceVariable('primary-7', "~'var(--@{ant-prefix}-primary-7)'");
+
+// Link
+replaceVariable('link-hover-color', '@primary-color-hover');
+replaceVariable('link-active-color', '@primary-color-active');
+
+replaceVariable(
+  'table-selected-row-hover-bg',
+  "~'var(--@{ant-prefix}-primary-color-active-deprecated-d-02)'",
+);
+
+replaceVariable(
+  'picker-basic-cell-hover-with-range-color',
+  "~'var(--@{ant-prefix}-primary-color-deprecated-l-35)'",
+);
+replaceVariable(
+  'picker-date-hover-range-border-color',
+  "~'var(--@{ant-prefix}-primary-color-deprecated-l-20)'",
+);
+
+replaceVariable(
+  'calendar-column-active-bg',
+  "~'var(--@{ant-prefix}-primary-color-active-deprecated-f-30)'",
+);
+
+replaceVariable(
+  'slider-handle-color-focus',
+  "~'var(--@{ant-prefix}-primary-color-deprecated-t-20)'",
+);
+replaceVariable(
+  'slider-handle-color-focus-shadow',
+  "~'var(--@{ant-prefix}-primary-color-deprecated-f-12)'",
+);
+replaceVariable(
+  'slider-dot-border-color-active',
+  "~'var(--@{ant-prefix}-primary-color-deprecated-t-50)'",
+);
+
+replaceVariable(
+  'transfer-item-selected-hover-bg',
+  "~'var(--@{ant-prefix}-primary-color-active-deprecated-d-02)'",
+);
+
+replaceVariable('alert-success-border-color', '@success-color-deprecated-border');
+replaceVariable('alert-success-bg-color', '@success-color-deprecated-bg');
+replaceVariable('alert-info-border-color', '@info-color-deprecated-border');
+replaceVariable('alert-info-bg-color', '@info-color-deprecated-bg');
+replaceVariable('alert-warning-border-color', '@warning-color-deprecated-border');
+replaceVariable('alert-warning-bg-color', '@warning-color-deprecated-bg');
+replaceVariable('alert-error-border-color', '@error-color-deprecated-border');
+replaceVariable('alert-error-bg-color', '@error-color-deprecated-bg');
+
+fse.writeFileSync(targetPath, variableContent, 'utf8');
+
+// eslint-disable-next-line no-console
+console.log(chalk.green('Success! Replaced path:'), targetPath);
diff --git a/scripts/generate-version.js b/scripts/generate-version.js
new file mode 100644
index 000000000..0370a17df
--- /dev/null
+++ b/scripts/generate-version.js
@@ -0,0 +1,10 @@
+const fs = require('fs-extra');
+const path = require('path');
+
+const { version } = require('../package.json');
+
+fs.writeFileSync(
+  path.join(__dirname, '..', 'components', 'version', 'version.tsx'),
+  `export default '${version}'`,
+  'utf8',
+);
diff --git a/webpack.build.conf.js b/webpack.build.conf.js
index c065f6b04..3341339b5 100644
--- a/webpack.build.conf.js
+++ b/webpack.build.conf.js
@@ -1,8 +1,36 @@
 // This config is for building dist files
+const chalk = require('chalk');
+const RemovePlugin = require('remove-files-webpack-plugin');
 const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
+const { ESBuildMinifyPlugin } = require('esbuild-loader');
+const DuplicatePackageCheckerPlugin = require('duplicate-package-checker-webpack-plugin');
 const getWebpackConfig = require('./antd-tools/getWebpackConfig');
-const IgnoreEmitPlugin = require('ignore-emit-webpack-plugin');
 const darkVars = require('./scripts/dark-vars');
+const compactVars = require('./scripts/compact-vars');
+
+function injectLessVariables(config, variables) {
+  (Array.isArray(config) ? config : [config]).forEach(conf => {
+    conf.module.rules.forEach(rule => {
+      // filter less rule
+      if (rule.test instanceof RegExp && rule.test.test('.less')) {
+        const lessRule = rule.use[rule.use.length - 1];
+        if (lessRule.options.lessOptions) {
+          lessRule.options.lessOptions.modifyVars = {
+            ...lessRule.options.lessOptions.modifyVars,
+            ...variables,
+          };
+        } else {
+          lessRule.options.modifyVars = {
+            ...lessRule.options.modifyVars,
+            ...variables,
+          };
+        }
+      }
+    });
+  });
+
+  return config;
+}
 
 function addLocales(webpackConfig) {
   let packageName = 'antd-with-locales';
@@ -22,13 +50,42 @@ function externalDayjs(config) {
   };
 }
 
+function injectWarningCondition(config) {
+  config.module.rules.forEach(rule => {
+    // Remove devWarning if needed
+    if (rule.test.test('test.tsx')) {
+      rule.use = [
+        ...rule.use,
+        {
+          loader: 'string-replace-loader',
+          options: {
+            search: 'devWarning(',
+            replace: "if (process.env.NODE_ENV !== 'production') devWarning(",
+          },
+        },
+      ];
+    }
+  });
+}
+
 function processWebpackThemeConfig(themeConfig, theme, vars) {
   themeConfig.forEach(config => {
     externalDayjs(config);
 
     // rename default entry to ${theme} entry
     Object.keys(config.entry).forEach(entryName => {
-      config.entry[entryName.replace('antd', `antd.${theme}`)] = config.entry[entryName];
+      const originPath = config.entry[entryName];
+      let replacedPath = [...originPath];
+
+      // We will replace `./index` to `./index-style-only` since theme dist only use style file
+      if (originPath.length === 1 && originPath[0] === './index') {
+        replacedPath = ['./index-style-only'];
+      } else {
+        // eslint-disable-next-line no-console
+        console.log(chalk.red('🆘 Seems entry has changed! It should be `./index`'));
+      }
+
+      config.entry[entryName.replace('antd', `antd.${theme}`)] = replacedPath;
       delete config.entry[entryName];
     });
 
@@ -45,14 +102,41 @@ function processWebpackThemeConfig(themeConfig, theme, vars) {
       }
     });
 
-    const themeReg = new RegExp(`${theme}(.min)?\\.js(\\.map)?$`);
+    // apply ${theme} less variables
+    injectLessVariables(config, vars);
+
     // ignore emit ${theme} entry js & js.map file
-    config.plugins.push(new IgnoreEmitPlugin(themeReg));
+    config.plugins.push(
+      new RemovePlugin({
+        after: {
+          root: './dist',
+          include: [
+            `antd.${theme}.js`,
+            `antd.${theme}.js.map`,
+            `antd.${theme}.min.js`,
+            `antd.${theme}.min.js.map`,
+          ],
+          log: false,
+          logWarning: false,
+        },
+      }),
+    );
   });
 }
 
-const webpackConfig = getWebpackConfig(false);
-const webpackDarkConfig = getWebpackConfig(false);
+const legacyEntryVars = {
+  'root-entry-name': 'default',
+};
+const webpackConfig = injectLessVariables(getWebpackConfig(false), legacyEntryVars);
+const webpackDarkConfig = injectLessVariables(getWebpackConfig(false), legacyEntryVars);
+const webpackCompactConfig = injectLessVariables(getWebpackConfig(false), legacyEntryVars);
+const webpackVariableConfig = injectLessVariables(getWebpackConfig(false), {
+  'root-entry-name': 'variable',
+});
+
+webpackConfig.forEach(config => {
+  injectWarningCondition(config);
+});
 
 if (process.env.RUN_ENV === 'PRODUCTION') {
   webpackConfig.forEach(config => {
@@ -60,7 +144,13 @@ if (process.env.RUN_ENV === 'PRODUCTION') {
     addLocales(config);
     // Reduce non-minified dist files size
     config.optimization.usedExports = true;
-
+    // use esbuild
+    if (process.env.ESBUILD || process.env.CSB_REPO) {
+      config.optimization.minimizer[0] = new ESBuildMinifyPlugin({
+        target: 'es2015',
+        css: true,
+      });
+    }
     config.plugins.push(
       new BundleAnalyzerPlugin({
         analyzerMode: 'static',
@@ -68,9 +158,25 @@ if (process.env.RUN_ENV === 'PRODUCTION') {
         reportFilename: '../report.html',
       }),
     );
+
+    if (!process.env.NO_DUP_CHECK) {
+      config.plugins.push(
+        new DuplicatePackageCheckerPlugin({
+          verbose: true,
+          emitError: true,
+        }),
+      );
+    }
   });
 
   processWebpackThemeConfig(webpackDarkConfig, 'dark', darkVars);
+  processWebpackThemeConfig(webpackCompactConfig, 'compact', compactVars);
+  processWebpackThemeConfig(webpackVariableConfig, 'variable', {});
 }
 
-module.exports = webpackConfig.concat(webpackDarkConfig);
+module.exports = [
+  ...webpackConfig,
+  ...webpackDarkConfig,
+  ...webpackCompactConfig,
+  ...webpackVariableConfig,
+];
diff --git a/webpack.config.js b/webpack.config.js
deleted file mode 100644
index 5e1fbf93c..000000000
--- a/webpack.config.js
+++ /dev/null
@@ -1,149 +0,0 @@
-const HtmlWebpackPlugin = require('html-webpack-plugin');
-const VueLoaderPlugin = require('vue-loader/dist/plugin').default;
-const WebpackBar = require('webpackbar');
-const path = require('path');
-const MiniCssExtractPlugin = require('mini-css-extract-plugin');
-
-const babelConfig = {
-  cacheDirectory: true,
-  presets: [
-    [
-      '@babel/preset-env',
-      {
-        targets: {
-          browsers: ['last 2 versions', 'Firefox ESR', '> 1%', 'not ie 11'],
-        },
-      },
-    ],
-    '@babel/preset-typescript',
-  ],
-  plugins: [
-    [
-      'babel-plugin-import',
-      {
-        libraryName: 'ant-design-vue',
-        libraryDirectory: '', // default: lib
-        style: true,
-      },
-    ],
-    ['@vue/babel-plugin-jsx', { mergeProps: false, enableObjectSlots: false }],
-    '@babel/plugin-proposal-optional-chaining',
-    '@babel/plugin-transform-object-assign',
-    '@babel/plugin-proposal-object-rest-spread',
-    '@babel/plugin-proposal-export-default-from',
-    '@babel/plugin-proposal-export-namespace-from',
-    '@babel/plugin-proposal-class-properties',
-  ],
-};
-
-/** @type {import('webpack').Configuration} */
-
-module.exports = {
-  mode: 'development',
-  entry: {
-    app: './examples/index.js',
-  },
-  stats: {
-    warningsFilter: /export .* was not found in/,
-  },
-  module: {
-    rules: [
-      {
-        test: /\.md$/,
-        loader: 'raw-loader',
-      },
-      {
-        test: /\.(vue)$/,
-        loader: 'vue-loader',
-      },
-      {
-        test: /\.(ts|tsx)?$/,
-        use: [
-          {
-            loader: 'babel-loader',
-            options: babelConfig,
-          },
-          {
-            loader: 'ts-loader',
-            options: {
-              transpileOnly: true,
-              appendTsSuffixTo: ['\\.vue$'],
-              happyPackMode: false,
-            },
-          },
-        ],
-        exclude: /node_modules/,
-      },
-      {
-        test: /\.(js|jsx)$/,
-        loader: 'babel-loader',
-        exclude: /pickr.*js/,
-        options: babelConfig,
-      },
-      {
-        test: /\.(png|jpg|gif|svg)$/,
-        loader: 'file-loader',
-        options: {
-          name: '[name].[ext]?[hash]',
-        },
-      },
-      {
-        test: /\.less$/,
-        use: [
-          { loader: 'style-loader' },
-          {
-            loader: 'css-loader',
-            options: { sourceMap: true },
-          },
-          {
-            loader: 'less-loader',
-            options: {
-              lessOptions: {
-                sourceMap: true,
-                javascriptEnabled: true,
-              },
-            },
-          },
-        ],
-      },
-      {
-        test: /\.css$/,
-        use: [
-          {
-            loader: MiniCssExtractPlugin.loader,
-            options: {},
-          },
-          'css-loader',
-        ],
-      },
-    ],
-  },
-  resolve: {
-    alias: {
-      'ant-design-vue/es': path.join(__dirname, './components'),
-      'ant-design-vue': path.join(__dirname, './components'),
-      vue$: 'vue/dist/vue.runtime.esm-bundler.js',
-    },
-    extensions: ['.ts', '.tsx', '.js', '.jsx', '.vue', '.md'],
-  },
-  devServer: {
-    historyApiFallback: {
-      rewrites: [{ from: /./, to: '/index.html' }],
-    },
-    hot: true,
-    open: true,
-  },
-  devtool: 'inline-cheap-module-source-map',
-  plugins: [
-    new MiniCssExtractPlugin({
-      filename: '[name].css',
-    }),
-    new HtmlWebpackPlugin({
-      template: 'examples/index.html',
-      filename: 'index.html',
-      inject: true,
-    }),
-    new VueLoaderPlugin(),
-    new WebpackBar(),
-  ],
-};