Assignee: @copilot
Summary
In shell/utils/dynamic-importer.js, 10 import* functions all follow the exact same 7-line structure: validate the name argument, throw if missing, and return a defineAsyncComponent(() => import(...)) call. The only difference between each function is the webpack chunk name and the import path prefix. This is ~70 lines of structural copy-paste inside a single file.
Duplication Details
Pattern: Repeated defineAsyncComponent factory with name guard
- Severity: Medium
- Occurrences: 10 functions
- Location:
shell/utils/dynamic-importer.js (lines 7–87)
Duplicated structure (repeated 10 times with minor variation):
export function importXxx(name) {
if (!name) {
throw new Error('Name required');
}
return defineAsyncComponent(() => import(/* webpackChunkName: "xxx" */ `@shell/path/${name}`));
}
Affected functions (lines 7–87):
| Function |
Chunk Name |
Import Path |
importCloudCredential |
cloud-credential |
@shell/cloud-credential/ |
importMachineConfig |
machine-config |
@shell/machine-config/ |
importLogin |
login |
@shell/components/auth/login/ |
importChart |
chart |
@shell/chart/ |
importList |
list |
@shell/list/ |
importDetail |
detail |
@shell/detail/ |
importEdit |
edit |
@shell/edit/ |
importDialog |
dialog |
@shell/dialog/ |
importDrawer |
drawer |
@shell/components/Drawer/ |
importWindowComponent |
components |
@shell/components/Window/ |
Similarly, 7 resolve* functions (lines 117–143) all follow:
export function resolveXxx(key) {
return require.resolve(`@shell/path/${ key }`);
}
Impact Analysis
- Maintainability: Any changes to input validation (e.g., better error messages, type checks) must be applied in 10 places.
- Bug Risk: Inconsistent whitespace between
if (!name) and if ( !name ) already exists across the functions, suggesting drift.
- Code Bloat: ~70 lines reducible to a factory pattern plus a lookup table.
Note: This file deliberately avoids ESLint and uses dynamic import() expressions. Webpack requires static string prefixes in template literals for code splitting to work correctly. Any refactoring must preserve the literal path prefix before the dynamic name segment — test with a production build to confirm chunk generation is not affected.
Refactoring Recommendations
-
Factory function approach — Create an internal createImporter(chunkName, pathPrefix) helper:
function createImporter(chunkName, pathPrefix) {
return function(name) {
if (!name) {
throw new Error('Name required');
}
// Each call site must still use a literal prefix for webpack analysis
return defineAsyncComponent(() => import(`@shell/${pathPrefix}/${name}`));
};
}
⚠️ Webpack magic comments and static path analysis may prevent fully generic factories. Validate with yarn build that chunks are named and split correctly.
-
Alternatively, consolidate the name guard into a single utility and keep each function body minimal:
function requireName(name) {
if (!name) throw new Error('Name required');
}
export function importList(name) {
requireName(name);
return defineAsyncComponent(() => import(/* webpackChunkName: "list" */ `@shell/list/${name}`));
}
This removes 3 duplicated lines per function without touching the import expression.
Implementation Checklist
Analysis Metadata
- Analyzed Files: 1 (
shell/utils/dynamic-importer.js)
- Detection Method: Structural code analysis
- Commit: 3331497
- Analysis Date: 2026-07-04T21:20:52Z
Generated by Duplicate Code Detector · ● 2.2M · ◷
Assignee:
@copilotSummary
In
shell/utils/dynamic-importer.js, 10import*functions all follow the exact same 7-line structure: validate thenameargument, throw if missing, and return adefineAsyncComponent(() => import(...))call. The only difference between each function is the webpack chunk name and the import path prefix. This is ~70 lines of structural copy-paste inside a single file.Duplication Details
Pattern: Repeated
defineAsyncComponentfactory with name guardshell/utils/dynamic-importer.js(lines 7–87)Duplicated structure (repeated 10 times with minor variation):
Affected functions (lines 7–87):
importCloudCredentialcloud-credential@shell/cloud-credential/importMachineConfigmachine-config@shell/machine-config/importLoginlogin@shell/components/auth/login/importChartchart@shell/chart/importListlist@shell/list/importDetaildetail@shell/detail/importEditedit@shell/edit/importDialogdialog@shell/dialog/importDrawerdrawer@shell/components/Drawer/importWindowComponentcomponents@shell/components/Window/Similarly, 7
resolve*functions (lines 117–143) all follow:Impact Analysis
if (!name)andif ( !name )already exists across the functions, suggesting drift.Refactoring Recommendations
Factory function approach — Create an internal
createImporter(chunkName, pathPrefix)helper:Alternatively, consolidate the name guard into a single utility and keep each function body minimal:
This removes 3 duplicated lines per function without touching the import expression.
Implementation Checklist
requireNameguard (or equivalent) to remove guard duplicationyarn buildand verify chunk names are correctAnalysis Metadata
shell/utils/dynamic-importer.js)