{"record":{"id":"a2a36411222a6c79","repo":"jeecgboot/JeecgBoot","slug":"addcomponent-type","errorCode":null,"errorMessage":"【addComponent】组件\"${type}\"已存在","messagePattern":"【addComponent】组件\"(.+?)\"已存在","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"jeecgboot-vue3/src/components/jeecg/JVxeTable/src/componentMap.ts","lineNumber":50,"sourceCode":"  JVxeTypes.rowNumber,\n  JVxeTypes.rowCheckbox,\n  JVxeTypes.rowRadio,\n  JVxeTypes.rowExpand,\n];\n\n/**\n * 注册组件\n *\n * @param type 组件 type\n * @param component Vue组件\n * @param spanComponent 显示组件，可空，默认为 JVxeNormalCell 组件\n */\nexport function addComponent(type: JVxeTypes, component: JVxeVueComponent, spanComponent?: JVxeVueComponent) {\n  if (excludeKeywords.includes(type)) {\n    throw new Error(`【addComponent】不能使用\"${type}\"作为组件的name，因为这是关键字。`);\n  }\n  if (componentMap.has(type)) {\n    throw new Error(`【addComponent】组件\"${type}\"已存在`);\n  }\n  componentMap.set(type, component);\n  if (spanComponent) {\n    componentMap.set(type + spanEnds, spanComponent);\n  }\n  // 代码逻辑说明: 【issues/860】生成的一对多代码，热更新之后点击新增卡死[暂时先解决]\n  import.meta.env.DEV && (window[JVxeComponents] = componentMap);\n}\n\nexport function deleteComponent(type: JVxeTypes) {\n  componentMap.delete(type);\n  componentMap.delete(type + spanEnds);\n  // 代码逻辑说明: 【issues/860】生成的一对多代码，热更新之后点击新增卡死[暂时先解决]\n  import.meta.env.DEV && (window[JVxeComponents] = componentMap);\n}\n\n/** 定义内置自定义组件 */\nexport function definedComponent() {","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/jeecgboot/JeecgBoot/blob/96fb33f5ec68516da0b0147da06b2eb0419e063a/jeecgboot-vue3/src/components/jeecg/JVxeTable/src/componentMap.ts#L32-L68","documentation":"addComponent stores components in a module-level Map keyed by JVxeTypes. If a type is already present in componentMap, re-registering throws to prevent silent shadowing of an existing cell. This typically surfaces during hot-module replacement (HMR): the registration module re-executes on save and tries to re-add already-registered components. The code has an issues/860 workaround that assigns the map to window in DEV for HMR recovery, but the duplicate guard itself still throws on a plain re-import.","triggerScenarios":"Calling addComponent for a type that was registered earlier in the same module load — most commonly during Vite HMR when registerThirdComp.ts or componentMap.ts is re-evaluated. Also triggered by importing the registration module twice (e.g. once eagerly and once lazily), or by a plugin that registers on every mount.","commonSituations":"Vite dev server HMR after editing a cell component or the registration file; dual registration from both registerThirdComp.ts and an @jeecg/online package; a Vue plugin that re-runs install on every component usage.","solutions":["Guard the registration with a componentMap.has(type) check before calling addComponent, or call deleteComponent first.","For HMR, ensure the registration runs once per module load and is idempotent (wrap in a flag or use the existing has-check).","Eliminate double-import paths: register each type in exactly one module.","If a plugin re-registers, move registration to app.initializeApp, not per-component install."],"exampleFix":"// before — throws on HMR re-evaluation\naddComponent(JVxeTypes.input, JVxeInputCell);\n\n// after — idempotent registration\nif (!componentMap.has(JVxeTypes.input)) {\n  addComponent(JVxeTypes.input, JVxeInputCell);\n}","handlingStrategy":"validation","validationCode":"import { componentMap } from './componentMapStore';\nfunction registerOnce(type, component, spanComponent?) {\n  if (componentMap.has(type)) return; // idempotent\n  addComponent(type, component, spanComponent);\n}","typeGuard":"const isRegistered = (type: JVxeTypes): boolean => componentMap.has(type);","tryCatchPattern":"try {\n  addComponent(type, component);\n} catch (e) {\n  // already registered (likely HMR); safe to ignore or call deleteComponent first\n}","preventionTips":["Make registration idempotent with a has() guard.","Register each type in exactly one module to avoid double imports.","Move registration to app init, not per-component plugin install."],"tags":["vxe-table","component-registration","hmr","frontend","duplicate"],"backgroundTag":null,"analyzedSha":"96fb33f5ec68516da0b0147da06b2eb0419e063a","analyzedAt":"2026-08-14T00:04:16.786Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}