You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vite@4.x + Ant Design@3.x + React@16 部署主题类型未知错误排查

Ant Design 3.x 迁移Vite部署时出现Unknown theme type: undefined, name: undefined错误排查

问题概述

将旧项目迁移至Vite后,本地运行正常,但部署到服务器时,Ant Design 3.x的withSuffix函数抛出错误:Unknown theme type: undefined, name: undefined。推测遍历的icons数组中混入了undefined项,但不确定具体触发原因,怀疑与Vite配置有关。

错误代码片段

抛出错误的withSuffix函数

export function withSuffix(name, theme) {
  switch (theme) {
    case "fill":
      return name + "-fill";
    case "outline":
      return name + "-o";
    case "twotone":
      return name + "-twotone";
    default:
      throw new TypeError("Unknown theme type: " + theme + ", name: " + name);
  }
}

调用该函数的代码

icons.forEach(function (icon) {
  _this2.definitions.set(withSuffix(icon.name, icon.theme), icon);
});

临时修复方案

修改withSuffix函数,移除默认抛出错误的逻辑,默认降级为outline主题,修改后项目本地和服务器均正常运行:

export function withSuffix(name, theme) {
  switch (theme) {
    case "fill":
      return name + "-fill";
    default:
    case "outline":
      return name + "-o";
    case "twotone":
      return name + "-twotone";
  }
}

项目配置

package.json

{
  "name": "ta",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "start": "vite --mode local",
    "start:dev": "vite --mode local-development",
    "start:qa": "vite --mode local-qa",
    "build:dev": "tsc && vite build --base=/ta-admin --mode development",
    "build:qa": "tsc && vite build --base=/ta-admin --mode qa",
    "build:staging": "tsc && vite build --base=/admin --mode staging",
    "build:prod": "tsc && vite build --base=/admin --mode production",
    "preview": "vite preview"
  },
  "dependencies": {
    "@ant-design/plots": "^1.2.4",
    "@material-ui/core": "^4.4.0",
    "@material-ui/icons": "^4.2.1",
    "@reduxjs/toolkit": "^1.9.2",
    "antd": "^3.19.3",
    "antd-virtual-select": "^1.1.2",
    "axios": "^1.3.0",
    "file-saver": "^2.0.5",
    "history": "^4.10.1",
    "html2canvas": "^1.4.1",
    "immutability-helper": "^3.0.1",
    "jquery": "^3.6.3",
    "jspdf": "^2.5.1",
    "keycloak-js": "^20.0.3",
    "less": "^4.1.3",
    "loadable-components": "^2.2.3",
    "lodash-decorators": "^6.0.1",
    "lodash.difference": "^4.5.0",
    "moment": "^2.29.4",
    "popper.js": "^1.16.1",
    "react": "^16.8.6",
    "react-dnd": "^9.4.0",
    "react-dnd-html5-backend": "^9.4.0",
    "react-dom": "^16.8.6",
    "react-html-parser": "^2.0.2",
    "react-intl": "^2.9.0",
    "react-intl-universal": "^2.6.11",
    "react-monaco-editor": "^0.31.0",
    "react-redux": "^8.0.5",
    "react-router-dom": "^5.3.4",
    "styled-components": "^5.3.6"
  },
  "devDependencies": {
    "@types/node": "^18.11.18",
    "@types/react": "^16.8.6",
    "@types/react-dom": "^18.0.10",
    "@types/react-router-dom": "^5.3.3",
    "@vitejs/plugin-react": "^3.0.0",
    "typescript": "^4.9.5",
    "vite": "^4.0.0"
  }
}

vite.config.ts

import { defineConfig, loadEnv } from "vite";
import react from "@vitejs/plugin-react";

const getApiHost = (npm_lifecycle_event: string) => {
  switch (npm_lifecycle_event) {
    default:
    case "start":
      return "http://localhost:8080";
  }
};

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), "");
  const scriptArray = env?.npm_lifecycle_script?.split(" ") || [];
  const basePortion = scriptArray.find((scriptPortion) => {
    return scriptPortion.includes("--base");
  });
  let outDir = basePortion ? basePortion.split("/")[1] : "build";
  const target = getApiHost(env.npm_lifecycle_event);
  const runningLocally = mode.includes("local");

  return {
    plugins: [react()],
    ...(runningLocally
      ? {
          define: {
            global: {},
          },
        }
      : {}),
    server: {
      port: 3000,
      open: true,
      proxy: {
        "/api": {
          target,
          changeOrigin: true,
          secure: false,
        },
      },
    },
    css: {
      preprocessorOptions: {
        less: {
          javascriptEnabled: true,
          additionalData: "@root-entry-name: default;",
        },
      },
    },
    build: {
      outDir,
      commonjsOptions: {
        transformMixedEsModules: true,
      },
    },
  };
});

根本原因分析

Ant Design 3.x的Icon模块采用老式CommonJS导出格式,Vite在生产构建时的模块转换(CommonJS转ES模块)和代码优化(树摇、压缩)流程中,对这类旧模块的解析出现异常,导致icons数组中混入了undefined项。本地开发模式下Vite的模块处理逻辑更宽松,不会触发该问题,但生产构建的严格优化暴露了兼容性缺陷。

优化解决方案

方案一:优化Vite的CommonJS转换配置

修改vite.config.ts中的commonjsOptions,明确指定包含Ant Design及其依赖的rc组件,确保模块转换完全覆盖:

build: {
  outDir,
  commonjsOptions: {
    transformMixedEsModules: true,
    include: [/node_modules\/antd/, /node_modules\/rc-.*/], // 精准匹配antd及相关依赖
  },
},

方案二:添加Legacy兼容插件(可选)

安装@vitejs/plugin-legacy插件,增强对旧模块的兼容性处理:

  1. 安装依赖:
npm install @vitejs/plugin-legacy --save-dev
  1. 修改vite.config.ts:
import legacy from '@vitejs/plugin-legacy';

export default defineConfig(({ mode }) => {
  // ... 其他配置
  return {
    plugins: [
      react(),
      legacy({
        targets: ['defaults', 'not IE 11'], // 按需调整目标浏览器
      })
    ],
    // ... 其他配置
  };
});

方案三:通过patch-package固化临时修复

如果不想修改Vite配置,可以用patch-package给Ant Design打永久补丁,避免每次安装依赖后重复修改:

  1. 安装依赖:
npm install patch-package --save-dev
  1. 修改node_modules/antd/es/icon/withSuffix.js(或对应路径的文件)为你修复后的代码
  2. 生成补丁:
npx patch-package antd
  1. 后续安装依赖时,补丁会自动应用。

内容的提问来源于stack exchange,提问作者Maaz Ahmad Khan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 14:35:40