@epxing/cli 0.5.0-beta.1 → 0.5.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/API.md +5 -5
- package/README.md +121 -98
- package/dist/cli.mjs +20 -12
- package/dist/lazy-lib.mjs +42 -27
- package/dist/lib-vite-config.mjs +1 -0
- package/dist/platform-version.mjs +48 -0
- package/dist/skills/epxing-frontend-vue3-migrate/SKILL.md +213 -144
- package/dist/skills/epxing-frontend-vue3-migrate/pitfalls.md +743 -498
- package/dist/skills/epxing-frontend-vue3-migrate/scripts/fix-eval-paths.cjs +255 -0
- package/dist/tools/chunks/7NAADJFP.mjs +45 -0
- package/dist/tools/chunks/{HSJSTJH6.mjs → 7YE2UHC6.mjs} +2 -2
- package/dist/tools/chunks/J7B2EWKH.mjs +8 -0
- package/dist/tools/chunks/{QL4QZFQT.mjs → U27ZPQAM.mjs} +3 -3
- package/dist/tools/chunks/VASFHXYG.mjs +251 -0
- package/dist/tools/epx-create/scaffold.mjs +67 -51
- package/dist/tools/epx-migrate/detect-vue3-risks.mjs +1 -1
- package/dist/tools/epx-migrate/fix-date-formats.mjs +1 -1
- package/dist/tools/epx-migrate/fix-theme-styles.mjs +1 -1
- package/dist/tools/epx-migrate/migrate.mjs +66 -266
- package/dist/tools/epx-migrate/verify-components.mjs +6 -6
- package/dist/vite.mjs +2 -2
- package/package.json +8 -6
- package/dist/tools/chunks/6CGUHPTB.mjs +0 -32
- package/dist/tools/chunks/H4POBCHI.mjs +0 -1
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/* eslint-disable no-console -- 输出已选择的平台版本 */
|
|
2
|
+
import http from 'node:http'
|
|
3
|
+
import https from 'node:https'
|
|
4
|
+
|
|
5
|
+
// Node 20 的双栈自动连接在部分 Windows 网络超时,查询 npm 时固定使用 IPv4。
|
|
6
|
+
function readMetadata (url) {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
const client = url.protocol === 'http:' ? http : https
|
|
9
|
+
const request = client.get(url, {
|
|
10
|
+
family: 4,
|
|
11
|
+
headers: { accept: 'application/vnd.npm.install-v1+json', 'cache-control': 'no-cache' },
|
|
12
|
+
timeout: 15000
|
|
13
|
+
}, response => {
|
|
14
|
+
if (response.statusCode !== 200) {
|
|
15
|
+
response.resume()
|
|
16
|
+
reject(new Error(`npm 返回 HTTP ${response.statusCode}`))
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
let body = ''
|
|
20
|
+
response.setEncoding('utf8')
|
|
21
|
+
response.on('data', chunk => { body += chunk })
|
|
22
|
+
response.on('error', reject)
|
|
23
|
+
response.on('end', () => {
|
|
24
|
+
try { resolve(JSON.parse(body)) } catch (error) { reject(error) }
|
|
25
|
+
})
|
|
26
|
+
})
|
|
27
|
+
request.on('timeout', () => request.destroy(new Error('npm 请求超时')))
|
|
28
|
+
request.on('error', reject)
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 测试阶段默认使用 beta;显式版本不访问网络,标签解析后固定到具体版本。
|
|
33
|
+
export async function resolvePlatformVersion (spec, registry = process.env.npm_config_registry || 'https://registry.npmjs.org/') {
|
|
34
|
+
if (spec && !/^(?:[~^]?\d+\.\d+\.\d+(?:-[\w.-]+)?|[a-z][\w.-]*)$/.test(spec)) throw new Error('--packages-version 需要 npm 版本、版本范围或标签')
|
|
35
|
+
if (spec && /^[~^]?\d/.test(spec)) return spec
|
|
36
|
+
const tag = spec || 'beta'
|
|
37
|
+
try {
|
|
38
|
+
const metadata = await readMetadata(new URL('@epxing%2fcore', registry.endsWith('/') ? registry : registry + '/'))
|
|
39
|
+
const tags = metadata['dist-tags'] || {}
|
|
40
|
+
const selectedTag = tags[tag] ? tag : !spec ? 'latest' : tag
|
|
41
|
+
const version = tags[selectedTag]
|
|
42
|
+
if (!version || !/^\d+\.\d+\.\d+(?:-[\w.-]+)?$/.test(version)) throw new Error(`npm 中没有可用的 ${tag} 版本`)
|
|
43
|
+
console.log(`平台独立包版本:${version}(${selectedTag})`)
|
|
44
|
+
return version
|
|
45
|
+
} catch (error) {
|
|
46
|
+
throw new Error(`无法查询 @epxing/core 的 ${tag} 版本:${error.message}。请检查 npm 源和网络,或用 --packages-version 指定具体版本。`)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -1,144 +1,213 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: epxing-frontend-vue3-migrate
|
|
3
|
-
description: epx
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
#
|
|
7
|
-
|
|
8
|
-
## 这是什么
|
|
9
|
-
|
|
10
|
-
epx 的产品/项目远程库(`window.library.<pkg>`,由 `FM_SYSTEM_WEBPACK` 配 url、运行时加载)
|
|
11
|
-
从 Vue2/webpack 迁到 Vue3/Vite,并可选切到「清单 + 组件按需加载」形态的完整流程与踩坑清单。
|
|
12
|
-
|
|
13
|
-
独立 CLI
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
4
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
1
|
+
---
|
|
2
|
+
name: epxing-frontend-vue3-migrate
|
|
3
|
+
description: epx 产品/项目的前端升级、Vue 升级(vue升级)、升级到 Vue3(升级到vue3)、Vue2 转 Vue3、框架升级与产品升级时使用。由 AI 协同迁移依赖、业务代码及 webpack/Vite 构建,逐组件接入平台主题与全局 CSS 变量并验收;也用于远程库按需打包、迁移包对比及升级后组件不渲染、样式丢失等静默失效排查。不用于无关项目的通用 Vue 升级、平台框架源码重写或后端升级。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 产品升级与迁移(独立包 + Vue3 + Vite)
|
|
7
|
+
|
|
8
|
+
## 这是什么
|
|
9
|
+
|
|
10
|
+
epx 的产品/项目远程库(`window.library.<pkg>`,由 `FM_SYSTEM_WEBPACK` 配 url、运行时加载)
|
|
11
|
+
从 Vue2/webpack 迁到 Vue3/Vite,并可选切到「清单 + 组件按需加载」形态的完整流程与踩坑清单。
|
|
12
|
+
|
|
13
|
+
独立 CLI 使用 `epxing` 命令,产品默认依赖 `@epxing/core`、`@epxing/components`、`@epxing/business` 等独立包。`upgrade` 是 `migrate` 的别名;版本留空查询最新 beta(无 beta 时回退 latest),并固定具体版本。`--epx-frame` 仅显式保留旧聚合模式。仓库原有 `pnpm epx` 是本地脚本,不等同于已安装的 CLI。
|
|
14
|
+
|
|
15
|
+
## 自然语言触发与 AI 执行范围
|
|
16
|
+
|
|
17
|
+
在 epx 产品/项目上下文中,用户说“前端升级”“Vue 升级”“升级到 Vue3”“把人事从 Vue2 升到 Vue3”或“一并升级旧框架”时使用本技能,无需用户先报技能名或 CLI 命令。仅询问升级能力时先解释;要求实际升级时按下述流程推进。
|
|
18
|
+
|
|
19
|
+
1. 先读取工程清单、应用与组件库入口、构建配置及 Git 状态,判断现有 Vue、框架依赖和构建方式;按「先判断升级类型」选择路径,不对已有 Vue3 工程重复执行 Vue2 转换。
|
|
20
|
+
2. 产品使用 Vue2 版 epx-frame 时,将框架依赖迁至新版独立包与产品代码适配作为同一升级任务,覆盖入口、组件继承、导入、路由、状态管理、插槽及样式。若工程内复制或修改过旧框架源码,先识别差异与公开 API 替代方案,不直接删除或覆盖;超出产品适配的框架源码改造需明确范围后再处理。
|
|
21
|
+
3. CLI 用于确定的机械转换;AI 审阅迁移报告,继续定位并修复可确认的人工项、构建失败和运行差异,不停在给出命令或罗列待办。保留产品业务和自定义内容;遇到缺少业务依据或环境的项,明确原因与下一步,不声称全部完成。
|
|
22
|
+
4. 按下文判据验证平台登录、菜单、配置首页、产品组件及最终库产物。技能匹配不额外授予安装、构建、提交或部署权限,按用户任务授权及项目规则执行。
|
|
23
|
+
|
|
24
|
+
**主题接入是产品升级的必做项**,包括已经使用 Vue3/独立包的产品。按 [E2](pitfalls.md#e2-产品项目样式必须跟随平台主题轴) 建立全量组件台账,逐个检查主题和全局 CSS 变量、修复可确认的问题,并记录实际验证结果。每个组件都要有结论;没有改代码、CLI 未告警或只是继承平台组件,也不能免检。按用途接入,不给图标、布局、文字、表单等一律加面板装饰。未检、失败或缺环境的组件保持未完成,不能用几个代表页代替全量组件验收。
|
|
25
|
+
|
|
26
|
+
**跨会话缺陷回归**:同时读取 [G 节](pitfalls.md#g-产品升级的跨会话缺陷回归),按组件实际能力逐项判断是否适用,复用 E2 台账记录命中项、证据和结论。已有 F 节修法直接引用,不重复机械修复;平台已修复的兼容问题仍要确认目标宿主版本包含修复。具体产品的配置失效和未解决问题只作为定位线索,不能泛化成全产品必须修改的源码规则。
|
|
27
|
+
|
|
28
|
+
审核详情空白、数据已返回但持续加载时,按 [F28](pitfalls.md#f28-审核详情空白加载遮罩残留与懒加载页签计数) 检查上下文参数的 DOM 透传、JSX 分支指令清理及懒加载配置时序,并在授权范围修复确定命中项。
|
|
29
|
+
|
|
30
|
+
Claude Code 项目技能放在 `.claude/skills/epxing-frontend-vue3-migrate/`,同步本文件、`pitfalls.md` 和 `scripts/`;技能描述供自动匹配,不能保证每次命中。未自动选中时可显式调用 `/epxing-frontend-vue3-migrate`。更新产品已有技能前先比较并保留其自定义内容;仓库修改不会自动更新产品副本或已发布 CLI。
|
|
31
|
+
|
|
32
|
+
## 先判断升级类型
|
|
33
|
+
|
|
34
|
+
| 当前工程 | 操作 |
|
|
35
|
+
| --- | --- |
|
|
36
|
+
| Vue2 / webpack 产品 | 先预览 `epxing upgrade . --transform-vue --to-vite`,审阅人工项后同命令加 `--apply` |
|
|
37
|
+
| Vue3 聚合包产品 | `epxing upgrade .` 预览独立包切换;仅仍用 webpack 时追加 `--to-vite` |
|
|
38
|
+
| 已使用独立包的 Vue3 产品 | `epxing upgrade .` 更新包版本与确定的补修,不重复执行 Vue2 转换 |
|
|
39
|
+
|
|
40
|
+
默认预览只读;`--apply` 要求目标 Git 工作树干净。需要复现指定版本时传 `--packages-version <版本>`。CLI 不自动安装平台依赖、构建、提交、部署或发布产品,按当前任务授权执行后续步骤。日期和主题的静态补修随迁移执行;动态来源仍需复核。
|
|
41
|
+
|
|
42
|
+
## 平台启动入口
|
|
43
|
+
|
|
44
|
+
新建平台产品默认使用 `createApp({ router: createFrameRouter() })`,依次安装 Components、Business 和产品插件后 mount。core 提供最外层路由根组件;Business 注册系统 App,在应用配置就绪后读取 FIRST_PAGE / MOBILE_FIRST_PAGE。不要把 business 的系统视图直接挂成最外层根组件。components 提供 AppIndex、登录和基础组件。
|
|
45
|
+
|
|
46
|
+
旧 CLI 的计数欢迎页仅在 main.js 与 App.vue 都保持原始模板时自动修复;自定义根组件、路由、store、HTTP 客户端保留,先确认它是平台产品还是完全自建应用,再按实际用途调整。`epxing scan .` 的 R4 提示尚未修复的原始欢迎页,不据此覆盖自定义内容。
|
|
47
|
+
|
|
48
|
+
`src/main.js` 负责本地开发启动;`src/index.js` 负责产品组件库安装和导出,库入口中不再次 createApp 或 mount。组件目录以收集入口为准,不固定为 hr;无构建产物时 `epxing verify .` 仅列源码候选,不能当作产物校验或运行验收通过。
|
|
49
|
+
|
|
50
|
+
启动前确认后端地址、客户端、系统和应用配置;验收登录、角色、菜单、PC/移动端首页,再验产品组件、路由与状态。入口、依赖及迁移规则以当前 CLI 创建模板、迁移器和组件校验器为依据,参见 [A5](pitfalls.md#a5-独立包升级后仍显示欢迎页或平台入口空白)。
|
|
51
|
+
|
|
52
|
+
**核心判断:这条链上的失败几乎全是静默的。** 构建绿、控制台干净、组件就是不出来。
|
|
53
|
+
所以每一步都要有**判据**,别靠"看着没报错"。
|
|
54
|
+
|
|
55
|
+
## 什么时候用
|
|
56
|
+
|
|
57
|
+
- 要把某个产品库迁到 Vue3 / 从 webpack 切到 Vite
|
|
58
|
+
- 要给某个产品库开按需打包(库超过 ~1MB 时才值得,见「按需值不值」)
|
|
59
|
+
- 排查远程库的诡异现象:组件不渲染 / 注册名不对 / 有组件没样式 /
|
|
60
|
+
登录首屏拉了整个库 / `[loadComponent] 找不到 epx-xxx` / `[vuex] duplicate getter key`
|
|
61
|
+
|
|
62
|
+
**不适用**:平台自身(epx-frame)的构建问题;页面配置层面的组件用法(那看 `epx-frame-web`)。
|
|
63
|
+
|
|
64
|
+
## 顺序(别调换)
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
① 预览并应用升级 epxing upgrade . → 审阅计划后追加 --apply
|
|
68
|
+
② .vue 转换 (同上,gogocode) → 逐个修构建报错
|
|
69
|
+
③ 切 Vite 换 vite.config.mjs → require.context → import.meta.glob
|
|
70
|
+
④ 跑起来 dev 壳验证 → 组件真渲染出来才算过
|
|
71
|
+
⑤ 验产品库形态 epxing lib / lib --full → 按需 / 完整库,验清单和真实平台渲染
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**先用 `npm run build:lib:full` 验证完整库,再验证默认懒加载产物**,分开定位 Vue3 转换和分片问题。
|
|
75
|
+
|
|
76
|
+
## 每步的判据
|
|
77
|
+
|
|
78
|
+
| 步骤 | 判据(不是"没报错") |
|
|
79
|
+
|---|---|
|
|
80
|
+
| ① 依赖迁移 | `MIGRATION-REPORT.md` 的人工清单**逐条看过**——里面写着的坑会真的咬人 |
|
|
81
|
+
| ② .vue 转换 | 使用工程本地 ESLint 校验改动源码;工具链缺失则先恢复并明确未验证项,不临时拉全局 ESLint |
|
|
82
|
+
| ③ 切 Vite | `npm run build:lib` exit 0 **且** `lib/` 里有 `index.js`/`index.css`/`index.deps.json` |
|
|
83
|
+
| ④ dev 壳 | 平台登录、角色、菜单与配置首页可用,产品组件确实显示;核对真实 DOM 和 CSS,不能仅凭注册数量判通过。E2 台账覆盖每个组件,按用途接入主题与全局变量并验证;样式隔离变更还须用最终产物通过 F15 的组件内、组件外及跨页面检查 |
|
|
84
|
+
| ⑤ 按需 | `index.manifest.json` 与入口实际收集的组件集合对齐,复核路径兜底名;源码候选、产物清单和线上参考分别记录 |
|
|
85
|
+
|
|
86
|
+
第⑤条那个"路径兜底名"是最容易漏的:注册名抽不到就退成 `hrcomponentsSearch` 这种,
|
|
87
|
+
**dev 壳看不出来**(dev 读运行时 `comp.name`),只在按需形态下炸。
|
|
88
|
+
|
|
89
|
+
## 快速排错
|
|
90
|
+
|
|
91
|
+
| 现象 | 多半是 |
|
|
92
|
+
|---|---|
|
|
93
|
+
| 组件不渲染,`[loadComponent] 找不到 epx-xxx` | 平台占位抢注 / 产品 install 没跑 |
|
|
94
|
+
| `__epxInstalledLibs__` 有记录但 app 里 0 个组件 | 记账写在 install 之前,产品幂等守卫空转 |
|
|
95
|
+
| 注册名变成 `xxxcomponentsYyy` | `extractName` 没抽到 `name`(按需形态特有) |
|
|
96
|
+
| 组件出来了但完全没样式 | 先查样式表是否加载、实际 DOM 能否匹配选择器;常见原因是 CSS 与 chunk 不同批(`data-v` hash 对不上),或根节点漏了 `.epx-xxx` 样式命名空间(F19) |
|
|
97
|
+
| 隔离测试样式正常,实际页面中继承组件的图片/标题失去样式 | 检查平台包装组件及 Element Plus 插槽的完整渲染链;根有 `data-v-*` 不代表插槽内后代也有。按 F15 核对选择器与继承值,在有效专属容器内局部使用 `:deep()` |
|
|
98
|
+
| 自定义卡片变成纯文本,背景、间距、字段布局同时丢失 | 按 F15 追踪局部 render 回调及插槽后代的作用域匹配,并检查继承、复制同套样式或使用相同回调结构的组件;逐项记录实际验证状态 |
|
|
99
|
+
| 升级后工具栏 `el-select` 把相邻按钮挤到下一行 | Element Plus 选择框默认宽度为 100%;Vue3 产品不再走旧 render 垫片的宽度兜底,按 F20 在产品工具栏显式设置宽度和布局 |
|
|
100
|
+
| 日期选择器显示错误日期,但绑定值/数据时点正确 | 控件还用 fecha 的 `yyyy-MM-dd`,Element Plus 使用 Day.js 的 `YYYY-MM-DD`;按 F21 自动修复产品/项目源码,原生 Vue3 包不依赖旧垫片 |
|
|
101
|
+
| CLI 日期扫描报 `document is not defined` | 旧 CLI 打包了浏览器版解析器,HTML 实体触发 DOM 解码;0.5.0-beta.8 已修复。先核对实际命令路径及版本,更新后重新预览并继续已授权升级,不修改业务实体、不添加假的 document、不跳过日期检查;更新后仍失败时保留完整错误栈继续定位 |
|
|
102
|
+
| 旧薪酬卡片显示标题时报 `reading 'compTitle'` | 检查 `$configs.propsData.compTitle`;旧库通过 Vue2 垫片兼容,源码升级时改为 `this.compTitle`(模板用 `compTitle`),按 F22 检查其它 propsData 读取 |
|
|
103
|
+
| 列表接口已有 `字段#`,对象/选项列仍显示 ID 或代码 | 检查单写 `renderField` / `renderColumnOperates` 是否还返回 `{ scopedSlots: { default } }`;按 F23 改成 Vue3 插槽对象,并在不依赖旧垫片的产品产物中验收名称和操作列 |
|
|
104
|
+
| 平台已切换字号、圆角或明暗,产品样式仍固定 | 按 E2 迁移硬编码及动态样式,消费平台主题变量;不在产品重新导入整套主题,不删除 scoped |
|
|
105
|
+
| 图片 404,路径是 `/assets/xxx.png` | 嵌套构建没继承 `assetsInlineLimit` |
|
|
106
|
+
| `Cannot read properties of undefined (reading 'i18n')` | recorder-core 执行序(模块图里没有那条边) |
|
|
107
|
+
| `[vuex] duplicate getter key` | 库被装了两次(本地 + 远程) |
|
|
108
|
+
| `[vite:vue] reading 'type'`(无行号,某 .vue) | gogocode 漏转元素上的 `slot="x"`(F1) |
|
|
109
|
+
| `组件注册名冲突:… copy.vue` | 垃圾副本文件撞名(F8,`find src -iname "*copy*"`) |
|
|
110
|
+
| `npm i` 显示成功但 vite/依赖没装上 | `node-sass`/`fibers` 原生编译挂、exit code 被管道吞(F7) |
|
|
111
|
+
| `[loadComponent] 找不到 epx-xxx`(本地新迁的库) | 源码版本落后线上部署、缺组件(`verify-components.mjs --online` 对齐) |
|
|
112
|
+
|
|
113
|
+
**详细根因、判据与修法见 [pitfalls.md](pitfalls.md)**:A 迁移工具 / B Vite 化 / C 按需 / D 联调 / E 主题 / **F gogocode 残留 & 换库(recruit 实证)**。
|
|
114
|
+
|
|
115
|
+
> **CLI 现已自动处理的机械项**(不用再手管,见 `tools/epx-migrate`):依赖表迁移、入口 `require.context`→`import.meta.glob`、
|
|
116
|
+
> 内联事件多语句补分号、`:prop.sync`→`v-model`、删 `node-sass`/`fibers`、`--to-vite` 生成 vite.config(含 resolve.extensions)、
|
|
117
|
+
> 第三方 Vue2-only 库 ⑥ 告警、`verify-components` 与线上组件清单对齐。**留给人工的就是 F 节那几类**:元素级 slot/slot-scope 结构转换、换库、编译残留定位。
|
|
118
|
+
|
|
119
|
+
**列表升级必查**:按 [F23](pitfalls.md#f23-列表已有字段名称却显示-id代码旧单写插槽返回协议) 同时核查 `renderField` / `renderColumnOperates` 的返回结构和 `renderTable` 的调用点,插槽对象须通过 `v-slots` 或 `h` 第三参传递,不能作为列属性 spread。覆盖普通列、分组子列和前后操作列,确认页面实际加载本批制品;即使 CLI 无告警、构建成功,也须实测 `字段#` 名称、操作按钮及分组表头,未验证不得将此项标为完成。
|
|
120
|
+
|
|
121
|
+
**本地制品接入必查**:使用本地制品替换远程产品库时,按 F23 的制品核验执行 HTTP 原字节比对、入口加载格式/MIME/缓存及分片检查;已构建文件应绕开 Vite 模块转换链。必须用同批制品实际点击列表“查看”等目标入口,不能只凭首页或源码预注册正常判定加载成功。空白时先区分脚本/组件加载失败、组件渲染异常和接口空列表,再核对配置与业务数据来源,按证据判定产品、平台或配置归属。
|
|
122
|
+
|
|
123
|
+
**本地包链接不等于加载源码**:核对安装包 exports 实际指向 src 还是 dist。修改本地链接平台源码后,若消费方读取 dist,应在授权范围重建对应包,并重启/强制刷新消费方 Vite 预构建缓存;记录实际运行参数声明、请求来源与制品时间。区分 main.js 安装产品源码的开发应用与远程 UMD/按需制品宿主,两者验收分别记录,不能互相代替。按 F28 实际切换全部目标页签后再报告本地修复结果。
|
|
124
|
+
|
|
125
|
+
**目标宿主共享依赖必查**:用户指定了运行地址时,以该宿主为验收目标,不能用本地新版包代替。按 F26 核对最终 deps 清单和共享 shim 实际使用的包/导出;预加载后应在 `__EPX_PACKAGES__` 对应命名空间拿到同步真身。旧 `window.frame` 有组件不代表独立共享包已发布组件;继承基类缺失时先修共享加载桥并发布宿主,再用新会话复验,不能给 `$component`/`upPage` 填空对象掩盖。
|
|
126
|
+
|
|
127
|
+
**当前角色必须迁移到平台上下文**:按 F27 扫描并修复当前角色 ID/code 的取值和消费点,ID 使用 `$currentRoleId`(或 `$currentRole?.id`),code 使用 `$currentRole?.code`。已继承平台基类或公共组件混入的直接使用;普通自定义组件接入 `@epxing/core` 的 `ComponentMixin`。不自行解析地址、不从 localStorage 恢复当前角色、不额外查询角色列表匹配当前角色;角色管理页的编辑值和业务角色字段须保留各自语义。已授权升级中由 AI 完成可确认的迁移,并验证旧地址、新菜单地址及角色切换。
|
|
128
|
+
|
|
129
|
+
**交互与布局升级必查**:按 [F24](pitfalls.md#f24-控件初值不回显弹窗打不开模型属性和-jsx-事件仍是-vue2-协议) 检查模板、JSX 和 VNode 的模型属性、更新事件、旧 props/on 容器及包装组件两端,保留目标控件仍公开的命名模型。按 F15 核对卡片/表格的实际分发入口及插槽后代的作用域,记录具体规则匹配与计算样式;不要批量删除 scoped,也不能把静态扫描通过记为逐组件运行验收。
|
|
130
|
+
|
|
131
|
+
**参数路径必须自动补修**:每次执行本技能,在目标依赖就绪后、构建前,由 AI 运行随技能提供的 [fix-eval-paths.cjs](scripts/fix-eval-paths.cjs),适用于 Vue2 迁移及已经标识 Vue3 的产品。按 [F25 自动执行流程](pitfalls.md#f25-页面有字段却查不到数据参数占位符中的-eval-依赖局部变量) 先预览,再对已授权升级范围内的确定项加 `--apply`;不能只提示用户手动改代码。脚本只自动处理参数占位符路径,复杂表达式或无法确认的 this 上下文报告复核;继续定位可确认的问题,并记录未解决项。通过 lint 和最终制品取数验证后才能关闭该项。此步骤由执行技能的 AI 调用,不代表已发布 CLI 自动增加了此功能。
|
|
132
|
+
|
|
133
|
+
> **本轮新增(postAppoint 实证)**:
|
|
134
|
+
> - `fix-jsx-vue2` 除自动改 4 类 JSX 属性(`domProps*`/`nativeOn*`/`scopedSlots=`),现在还**报告** `<script>` 区的 `slot="xxx"` 具名插槽(第 5 类,需人工改 `v-slots`——因要重组 JSX 结构故不自动改;甄别见 F14);
|
|
135
|
+
> - `detect-vue3-risks.mjs`(`node tools/epx-migrate/detect-vue3-risks.mjs <项目>`)仅提示待复核模式:R1 = extends+scoped+无 template+裸类选择器,退出码 2 可用于 CI 提醒复核。命中不证明样式失效,未命中也不证明隔离安全;不要为消除告警批量删 scoped 或替换成 `:deep()`,按 F15 用实际产物验证。
|
|
136
|
+
|
|
137
|
+
**样式隔离默认保留**:JSX/render、无 template 或继承组件均不能作为删除 scoped 的依据;隔离测试正常也不能排除实际页面中包装组件/插槽链造成的作用域失配。用最终产物检查实际页面的失效元素、祖先和选择器,确认后优先保留 scoped,在有对应作用域属性的专属容器内对必要后代使用 `:deep()`。若确须去掉 scoped,根命名空间、全部选择器隔离和组件外回归须同时完成,不可留下“先去 scoped、稍后补隔离”的中间结果。详见 F15。
|
|
138
|
+
|
|
139
|
+
**日期格式必须自动补修(产品和项目都适用,含已标识 `runtime: vue3` 的工程)**:迁移器会在不依赖 gogocode 的阶段修复日期控件 `format`、`value-format/valueFormat` 的静态旧 token,覆盖 template、JSX 和常见 render 写法,并将文件/行号写入报告。仅补日期问题时,在平台工程运行 `node tools/epx-migrate/fix-date-formats.mjs <目标工程> --apply`,不用重跑整个依赖迁移。默认不带 `--apply` 为只读预览。
|
|
140
|
+
|
|
141
|
+
执行技能时,若自动修复器或发布前扫描发现动态格式变量、配置对象、函数/展开属性,继续追踪实际来源并修复能确认的旧格式;不能只记录“人工检查”便算完成。无法确认用途或缺少源配置的项才保留为未解决,并写明原因。不要全仓替换 `yyyy/dd`,也不改后端协议、其它日期库、分钟 `mm` 或星期 `ddd/dddd`。用最终产物核对初始回显、选择后的绑定值和请求日期一致;例如 `2026-10-20` 不能显示成 `2026-02-01`。详见 [F21](pitfalls.md#f21-element-plus-日期格式-token-迁移遗漏hr-历史组织机构图)。
|
|
142
|
+
|
|
143
|
+
## 迁移完怎么验:迁移包 vs 线上 三方对比(postAppoint / recruit / hr 实证)
|
|
144
|
+
|
|
145
|
+
构建绿 ≠ 与线上等价。把「本地新迁的包」摆到线上同一平台、同一后端、同账号,逐页对比,是唯一可靠验收。
|
|
146
|
+
|
|
147
|
+
**三组环境**:① 线上(原样)② 本地平台 dist + 线上旧包(只换平台,作基线)③ 本地平台 dist + 本地新迁包(实验组)。①↔③ 看迁移包对不对,②↔③ 把「平台的锅 / 包的锅」分开。
|
|
148
|
+
|
|
149
|
+
**工装(只读、不改项目任何文件)**:
|
|
150
|
+
- 起个小服务(如 `:4183`)把 `/file-server/npm/test/web_<产品>/*` 路由到本地 `<产品>/lib/*`、其余 `/file-server/*` 302 回源线上(图片等照常,避免「反代没转发」式误报);
|
|
151
|
+
- 平台 `dist/assets/js/config.js` 末尾追加地址改写钩子,把 `web_<产品>` 的 script/link/fetch 指到该服务——平台 `util.js` 对含 `http` 的 id **原样返回**,所以改 `MINIO_IP` 无效,**必须在 script/link/fetch 层改写**;
|
|
152
|
+
- ⚠️ 线上同一产品可能有**两个包路径**(如 `web_post` 在用、`web_postAppoint` 废弃,二者组件同名):先 `performance` 看平台实际加载哪个,工装两个前缀都拦;
|
|
153
|
+
- ⚠️ 每次 `build:pre` 重建 dist 会**冲掉**钩子——重装并 `location.reload()`(同文档 hash 跳转不重载),再用 `performance` 确认 `web_<产品>` 的 chunk 确实来自本地服务,才开始采数据。
|
|
154
|
+
|
|
155
|
+
**后台标签页定时器冻结(采数据必踩,否则满屏假象)**:Chrome 后台/被遮挡标签页里页面自身的 `setTimeout`/`setInterval`/`requestAnimationFrame` 会被密集节流甚至冻结(几十秒零触发),表现为「列表空 / echarts 不画 / 数据延迟出现」——极易误判成缺陷。页内自动化脚本 sleep 一律走 **Web Worker 定时器**(`new Worker(URL.createObjectURL(new Blob(['self.onmessage=e=>setTimeout(()=>self.postMessage(1),e.data)'])))` + 页面侧回调);应用自己的定时器同样被冻,采数据前把该 tab 切前台、或注入 setTimeout/rAF 垫片,空页先复核再定论。截图 / resize 都**不解冻**。
|
|
156
|
+
|
|
157
|
+
**运行时实证判据(别靠肉眼 / 文本 / 静态 grep)**:
|
|
158
|
+
- 组件在不在:`#app.__vue_app__._context.components` 数量 / 组件实例的 `$slots` 键;
|
|
159
|
+
- 样式生不生效:`getComputedStyle(el)` 比对(容器高度是否塌陷 0、色值 / 尺寸是否对齐线上);
|
|
160
|
+
- 样式是否泄漏:涉及 scoped、`:deep()` 或全局样式变更时,用最终懒加载产物记录外部同名元素(如 `.avatar`、`.container`)加载组件前后的计算样式;覆盖组件加载后、离开页面及进入其他页面的状态。组件内有效且组件外不受影响,才能验收(F15);
|
|
161
|
+
- 工具栏选择框与按钮:核对选择框宽度、父容器布局及 `getBoundingClientRect()` 的纵向中心位置;按 F20 检查升级后不再享有的旧垫片默认值,同时确认表单内整行选择框仍按设计占满可用宽度;
|
|
162
|
+
- 差异定性:`el-table` 固定列会复制一份 DOM(Vue2 Element UI 行数翻倍、Vue3 Element Plus 不翻)——比对「共 N 条 / 首行文本」而非 DOM 元素数,否则把「翻倍」误当差异;
|
|
163
|
+
- **静态 grep 到 Vue2 写法 ≠ 运行时一定失效**:失效与否取决于消费方 / 是否被平台全局样式兜住 / 组件运行时兼容(如 JSX `slot=` 在 el-popover reference 失效、在 el-dropdown 正常),必须运行时实证再判改不改。
|
|
164
|
+
|
|
165
|
+
## 按需值不值(实测,别想当然)
|
|
166
|
+
|
|
167
|
+
同一平台上只换 hr 的打包形态,Fast-3G 限速、每组 3 次取中位数:
|
|
168
|
+
|
|
169
|
+
| 形态 | 内容可见 | 关键路径 |
|
|
170
|
+
|---|---|---|
|
|
171
|
+
| 整体单体 | **11.1 s** | 1467 K / 49 请求 |
|
|
172
|
+
| 按需(含预取) | **13.5 s** | 1523 K / **107 请求** |
|
|
173
|
+
| 按需(关预取) | **11.8 s** | 1177 K / 49 请求 |
|
|
174
|
+
|
|
175
|
+
**按需没提速,甚至略慢**——省下的 290 KB 被多出来的往返吃掉了。
|
|
176
|
+
真正的大头是平台重建(旧平台 20–59 s → 新平台 11 s)。
|
|
177
|
+
|
|
178
|
+
所以按需的价值是**防止劣化**(库继续长大时首屏不跟着涨),不是当下提速。
|
|
179
|
+
当前 CLI 的 `epxing lib` 默认按需构建;小型产品或无需分片时可使用 `epxing lib --full`。选择依据是实际宿主、请求数与渲染测试,不用旧案例中的体积阈值作为统一开关。
|
|
180
|
+
|
|
181
|
+
## 部署前必查
|
|
182
|
+
|
|
183
|
+
1. **平台支不支持按需 ABI**:抓线上平台 bundle `grep registerLazyLibrary`。
|
|
184
|
+
没有就只能走降级②(壳自建 wrapper),没有集中预取、`deps.json` 也没人读——
|
|
185
|
+
**平台不先升级,产品这边开按需是白开**。
|
|
186
|
+
2. **按需形态必须传整个 `lib/` 目录**,不是 `index.js` + `index.css` 两个文件。
|
|
187
|
+
`FM_SYSTEM_WEBPACK` 里仍只配那两条 url,其余按相对路径取。
|
|
188
|
+
3. **`chunks/` 的 `import()` 需要文件服务给 CORS 头**,跨域没配会整库降级。
|
|
189
|
+
4. `index.deps.json` **必须与 index.js 同目录同名一并上传**,漏传不报错但精确 ensure 会静默退化。
|
|
190
|
+
5. 样式隔离有改动时,逐个核对修改的 style 块和最终 CSS;完成 F15 的组件外同名元素及跨页面验收。构建和静态扫描通过不能替代这一步;未测项明确记录为待验证。
|
|
191
|
+
6. 核对 E2 主题台账与入口收集、内部子组件及最终产物清单,确保每个组件有检查与运行结论。未检查、未验证、适配失败或缺少业务依据的项逐条列明,不得将升级标记为全部完成;未发现样式问题的组件也要保留核查证据。
|
|
192
|
+
7. 按 G 节核对适用的交互、上下文、浮层、表格、设计器和性能问题。区分已检查不适用、已验证通过、已改待验证和阻塞;临时浏览器修正、平台兼容单测或旧会话交付记录,不能作为当前产品新制品已通过的证据。
|
|
193
|
+
8. 使用本地替换库验收时,记录入口、CSS、清单和实际加载分片的响应与磁盘一致、入口加载方式正确,以及详情页实测结果。存在加载语法错误时先修接入;接口返回空列表时记录查询参数与配置依据,不为填充页面写入默认业务数据。
|
|
194
|
+
9. 核对 F27 当前角色迁移:ID/code 与接口及权限判断语义一致;旧含角色地址、新不含角色菜单地址、切换角色及缓存组件复用均取当前应用角色。普通组件已接入公共混入,未引入地址/存储兜底或重复初始化。
|
|
195
|
+
|
|
196
|
+
## 常见错误
|
|
197
|
+
|
|
198
|
+
- **只看 dev 壳就以为好了** —— dev 走 `import.meta.glob` + 运行时 `comp.name`,
|
|
199
|
+
按需形态那几个 bug 一个都不走。要验按需必须用构建产物。
|
|
200
|
+
- **两个构建并发写同一个 `lib/`** —— 实测会丢文件。`build:component` 第 1 趟
|
|
201
|
+
`emptyOutDir:true` 会清空整个目录,跑一半断了就只剩残缺产物。
|
|
202
|
+
- **拿"构建 exit 0"当验证** —— 这条链上大部分故障构建期完全看不出来。
|
|
203
|
+
- **把窗口/阈值调大当修复** —— 比如 `extractName` 的字符窗口,调大只是挪门槛。
|
|
204
|
+
|
|
205
|
+
## 库构建命令约定
|
|
206
|
+
|
|
207
|
+
CLI 0.5.0-beta.11 起,按需库 CSS 随各自 JS 同步注入,index.css 保留空文件兼容旧加载 URL;不能再以它包含全部组件样式验收。检查单组件加载前后样式、共享样式去重、资源路径与整库兜底。可视化、设计器与预览组件不后台预取,实际使用仍加载;新壳在旧平台关闭后台预取,平台支持 supportsPrefetchExclude 后普通组件可选择性预取。产品使用本地 CLI 插件,须更新产品依赖并重建整个 lib,不能只更新全局命令。
|
|
208
|
+
|
|
209
|
+
库构建分支须设置 `build.copyPublicDir: false`,避免旧 `public/cmaps`、`public/index.html` 原样混入 `lib/`;应用构建仍保留所需静态资源,不能删除源 public 目录。验收懒加载和全量库目录均无多余应用入口;若 index.html 不来自 public,继续检查是否误走 app 模式或自定义复制插件。已有动态/展开构建配置由 AI 按实际分支核对,不能跳过报告项。
|
|
210
|
+
|
|
211
|
+
升级收尾必须复查 `package.json`:标准 `build:lib` 应为 `node build-lib.mjs`,不得残留 `--full`;全量参数放在 `build:lib:full`。CLI 0.5.0-beta.9 补齐旧标准入口带 `--full` 的自动迁移。自定义构建或入口文件报告待接入时,由 AI 在已有升级授权内核对并保留必要步骤,不能将“保留原命令”当成默认懒加载已完成。
|
|
212
|
+
|
|
213
|
+
创建与升级后的标准工程使用 `npm run build:lib` 默认懒加载;全量构建使用 `npm run build:lib --full` 或 `npm run build:lib:full`。构建入口同时识别 `--full` 参数与 npm 透传的 `npm_config_full`。保留 `build:lib:lazy` 旧入口。升级已有 Vue3 工程也须核对 package.json 与 build-lib.mjs;自定义脚本或同名文件不可覆盖,继续人工接入并保留原构建步骤。懒加载上传整个 lib/,包含 chunks、清单与兜底包。
|