一键导入
record-bug-fix-memory
当用户要求在 bug 已经定位并修复后,记录排错经验、事故结论、AI 记忆更新、复盘摘要或本地 MCP 记忆时使用。这个技能只负责沉淀“发生了什么、为什么会发生、如何修好、以后要记住什么”,不要把它用于实际修复 bug。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
当用户要求在 bug 已经定位并修复后,记录排错经验、事故结论、AI 记忆更新、复盘摘要或本地 MCP 记忆时使用。这个技能只负责沉淀“发生了什么、为什么会发生、如何修好、以后要记住什么”,不要把它用于实际修复 bug。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | record-bug-fix-memory |
| description | 当用户要求在 bug 已经定位并修复后,记录排错经验、事故结论、AI 记忆更新、复盘摘要或本地 MCP 记忆时使用。这个技能只负责沉淀“发生了什么、为什么会发生、如何修好、以后要记住什么”,不要把它用于实际修复 bug。 |
使用这个技能,把已经完成的排错结果沉淀成可复用的长期记忆。
目标是保存根因、有效修复路径、错误假设和验证证据,让后续 agent 不再重复同样的弯路。
核心原则:记录决策链,不记录流水账。
在以下场景使用这个技能:
以下情况不要使用这个技能:
开始写记忆前,必须能回答下面六个问题:
如果有任何一个问题答不上来,先完成排错,不要提前写记忆。
CLAUDE.md、AGENTS.md、GEMINI.mdgotcha、decision 或 problem-solution默认规则:只要这条经验会影响整个仓库里的未来 agent,就优先写入三个根级 AI 记忆文档,不要埋进包级备注里。
每条记忆至少要覆盖这六件事:
使用简洁、面向未来复用的结构:
问题现象:...根因:...关键误导点:...有效修复:...验证方式:...后续约束:...这些句子应该帮助未来 agent 快速做对事,而不是复述完整排错过程。
当用户要求“补充 AI 记忆”时,不要只写当次 bug 的表面结论。先检查这次问题是否落在仓库已有事故模式里,再把对应经验合并写入记忆。
阅读提示:下面每条事故以 加粗维度标题 + 独立段落 排版,便于扫读;同类问题请在对应条目下增补,避免重复开新段落。
packages/vue-element-cui 的 vite@8 构建事故问题现象
vite:css-post 的 path 类型错误,通常发生在 CSS 资源产物处理时。实际根因
rollupOptions.output.assetFileNames 直接返回 assetInfo.name,当 CSS 资源名缺失时会返回 undefined。有效修复
assetInfo.name ?? "assets/[name][extname]"。记忆重点
后续约束
packages/vue-element-cui-nuxt 的 nuxt dev 启动事故问题现象
.nuxt 产物、缺失组件库样式产物,或出现 #app-manifest 相关错误。实际根因
.nuxt 目录事先存在。有效修复
dev/build 加 nuxt prepare 前置;给 @eams-monorepo/vue-element-cui 和 @eams-monorepo/vue-element-cui/styles 配源码别名;显式关闭当前模板链不稳定的 experimental.appManifest。记忆重点
后续约束
dist 已存在这个前提上。packages/vue-element-cui-nuxt 的文档站客户端 hydration 事故问题现象
实际根因
dayjs.min.js does not provide an export named 'default',后续还会串出 @braintree/sanitize-url、debug、mermaid 的 ESM/CJS 兼容问题。有效修复
extends: ["shadcn-docs-nuxt"] 不变;优先在 nuxt.config.ts 的 Vite 层做兼容修正,例如 dayjs -> dayjs/esm/index.js、mermaid -> mermaid/dist/mermaid.esm.mjs、debug -> ./shims/debug.ts,并补齐 vite.optimizeDeps.include、vite.resolve.dedupe = ["dayjs"]、vite.ssr.noExternal = ["debug"];tailwind.config.js 只做内容扫描兜底,不把样式当根因。记忆重点
后续约束
packages/vue-element-cui-nuxt 的稳定启动基线问题现象
实际根因
有效修复
extends: ["shadcn-docs-nuxt"]、单语 zh-CN i18n、ogImage.enabled = false、icon.clientBundle.scan = true、vite.ssr.noExternal 等最小可用组合。记忆重点
后续约束
packages/vue-element-cui-nuxt 的单语文档与 i18n 误用问题历史现象
/components 页面出现 Cannot read properties of undefined (reading children) 之类的 500 错误,也带来过多余的 locale 路径处理。共通根因
记忆重点
defaultLocale/locales 路线”,不要把历史上的不同修法混写成一个结论。后续约束
simple-git-hooks 钩子安装到假 .git 目录导致 lint-staged 从未触发问题现象
git commit 时 lint-staged 和 commitlint 均未触发,暂存区文件未被格式化,提交信息未被校验。实际根因
01s-2603-13eams/(.git 在这一层),而 pnpm monorepo 工作区在其子目录 eams-frontend-monorepo/。eams-frontend-monorepo/ 内存在一个假的 .git 目录(仅含 hooks/ 子目录,无 HEAD、config 等),simple-git-hooks 在 postinstall 时从 monorepo 目录向上查找 .git,先命中了这个假目录,于是把钩子安装到了 eams-frontend-monorepo/.git/hooks/。但 Git 执行提交时查找的是真正的 01s-2603-13eams/.git/hooks/(里面只有 .sample 文件),钩子从未被执行。关键线索
git rev-parse --git-dir 返回 01s-2603-13eams/.git,而 ls eams-frontend-monorepo/.git/ 只有一个 hooks/ 子目录且无任何 git 元数据文件,证实这是 simple-git-hooks 自行创建的假 .git。对比真正的 .git/hooks/ 目录——里面没有任何非 .sample 钩子文件,直接确认钩子装错了位置。有效修复
git config core.hooksPath eams-frontend-monorepo/.git/hooks,让 Git 从 monorepo 的钩子目录读取钩子;(2) 更新 simple-git-hooks.mjs,钩子命令加 cd eams-frontend-monorepo 前缀,使 npx 能在 monorepo 目录下找到依赖和配置;(3) commit-msg 钩子用 ROOT=$(pwd) 先保存仓库根绝对路径,cd 后用 "$ROOT/$1" 拼出提交信息文件的完整路径(因为 $1 是相对于仓库根的路径,cd 后会失效)。验证方式
git commit --allow-empty -m "test: hook trigger test" 后看到 lint-staged 输出 → No staged files found.,commitlint 也未拒绝合法信息,确认两个钩子均正常触发。后续约束
git rev-parse --git-dir 与 simple-git-hooks 实际写入钩子的位置是否一致。不要假设 .git 目录和 package.json 在同一层。删除假 .git 无效——simple-git-hooks 会重新创建,必须配合 core.hooksPath 使用。packages/vue-element-cui-nuxt 的 MDC 文档图标丢失事故(prettier 误格式化)问题现象
/getting-started、/components、/guidelines、/updates 页面卡片中的图标全部消失,title:、icon:、to: 等 props 变成了纯文本直接渲染在页面上。实际根因
prettier 在格式化 .md 文件时,会在 MDC 组件声明行(如 ::card)与 YAML frontmatter 起始标记(---)之间自动插入一个空行。MDC 解析器要求两者紧贴、不得有空行,一旦有空行,--- 被解析为 <hr> 标签,所有 YAML 内容变成段落文本,props 全部失效。关键误导点
SmartIcon 组件缺失,花时间检查 icon 库配置。应该先看 HTML 源码——HTML 中根本没有 icon 元素,说明 props 从未被解析。有效修复
.prettierignore,添加 packages/vue-element-cui-nuxt/content/**/*.md;(2) 在 prettier.config.mjs 的 overrides 中为该路径添加 requirePragma: true 双重保险;(3) 手动还原被格式化破坏的所有 ::card\n---(去掉中间空行)。验证方式
Invoke-WebRequest http://localhost:3001/getting-started 返回的 HTML 中包含 i-lucide:download、i-lucide:rocket、i-lucide:life-buoy、i-lucide:arrow-left-right 四个 icon class。后续约束
.prettierignore 中必须覆盖所有 nuxt content 目录;排查图标消失时,先看 HTML 源码中是否存在 icon 元素,而不是先查图标库配置。packages/vue-element-cui-nuxt 的 ::demo-playground 渲染失败事故(MDC 容器语法错误,2026-03)问题现象
::demo-playground、title:、#preview、#code 等原始文本直接渲染;浏览器 console 出现 Hydration completed but contains mismatches 与大量 hydration node mismatch 警告。实际根因
demo-playground 容器不是按 MDC 语法书写,典型错误包括:(1) 写成 ## ::demo-playground(被当成标题);(2) frontmatter 顺序错误(title/description 在前,--- 在后);(3) 容器开闭符不匹配。关键误导点
DemoPlayground 组件实现或 Nuxt 依赖兼容问题。实际上首个高价值线索是“正文出现 marker 裸文本 + hydration mismatch 同时出现”,应优先回查 markdown 容器语法。有效修复
::demo-playground + 紧跟 --- frontmatter + :: 闭合,并保持 #preview 与 #code 在容器内部;批量修改后抽样回归多个路由。验证方式
::demo-playground/#preview/#code/title: 裸文本;(3) demo 标题和描述(来自 frontmatter)正常渲染。后续约束
## ::demo-playground;禁止打乱 frontmatter 顺序;批量替换脚本只允许改目标容器片段,必须先抽样再全量,避免误改其他 ::: 容器。packages/vue-element-cui-nuxt 的 Nuxt SSR i18n 版本冲突事故(pnpm 依赖提升)问题现象
nuxt dev 启动后所有页面返回 500 错误,错误信息为 Error: (0, __vite_ssr_import_0__.registerMessageResolver) is not a function。实际根因
@intlify/core-base 存在多个版本(9.1.9 和 11.x)同时存在于依赖树中。shamefully-hoist=false 使 pnpm 按隔离模式管理依赖,Vite SSR 解析时命中了旧版 9.1.9(缺少 registerMessageResolver),而非 vue-i18n@11.x 所需的 11.x 版本。升级 shamefully-hoist=true 后,又出现旧版 sass@1.26.8 被提升,导致 sass.initAsyncCompiler is not a function。关键误导点
vite.ssr.noExternal、vite.resolve.alias、vite.resolve.dedupe 等 nuxt.config.ts 配置,全部是无效方向;正确方向是强制 pnpm 在整个 workspace 中使用单一版本,而不是在 Vite 层绕过。有效修复
.npmrc 中改为 shamefully-hoist=true;(2) 在 pnpm-workspace.yaml 的 overrides 中添加 "@intlify/core-base": "11.3.0"、"@intlify/shared": "11.3.0"、"sass": "^1.98.0";(3) 根 package.json 中升级 vue-i18n 到 "11.3.0";(4) 在 Cursor 外部的终端运行 pnpm install 使 overrides 生效。验证方式
node_modules/@intlify/core-base/package.json 中 version 字段为 11.3.0。后续约束
is not a function 错误,先用 pnpm why <package> 排查是否存在多版本实例,再通过 pnpm-workspace.yaml 的 overrides 强制单一版本;不要第一反应去改 nuxt.config.ts 的 Vite 层配置。.node 原生文件锁导致 pnpm install 失败问题现象
pnpm install 时,报 EPERM: operation not permitted, unlink 'node_modules/@oxc-parser/binding-win32-x64-msvc/parser.win32-x64-msvc.node',安装回滚,依赖变更无法生效。实际根因
@oxc-parser 原生 .node 文件的 Windows 文件锁,pnpm 无法删除该文件来完成依赖更新,导致整个安装事务回滚。有效修复
pnpm install,绕开 IDE 文件锁。验证方式
pnpm install 结束后无 EPERM 错误,pnpm-lock.yaml 正确更新。后续约束
@oxc-parser、esbuild、@swc/*)时,必须在 Cursor 外的终端运行 pnpm install;Cursor 内置终端只用于读取日志,不用于执行 install。.gitattributes 与 eol=lf 导致的 CRLF/LF「幽灵」差异(2026-03)问题现象
eams-frontend-monorepo/README.md 在多个 f1-* 子分支上永远显示已修改(M),切换分支也不消失,阻塞合并;git diff 往往只显示整文件「换行符变化」而无实质内容差异。实际根因
.gitattributes 已规定文本文件 eol=lf,Git 检出时把工作区写成 LF,但各分支索引里该文件的历史 blob 仍是 CRLF;索引与工作区行尾策略不一致,形成持续脏状态。关键误导点
git add --renormalize 后提交,否则切回即复现。有效修复
git add --renormalize <path>(或按需全库 git add --renormalize .)并提交,使对象库与 .gitattributes 一致;在 monorepo eams-frontend-monorepo/.editorconfig 的 [*] 下增加 end_of_line = lf,减少 Windows 下新文件默认 CRLF。将各子分支改动收拢到 f1 时,合并提交说明须过 commitlint,使用 chore: merge <branch> into f1 等形式,避免使用非法 type(如 merge:)导致合并不完成。验证方式
f1-* 分支上 git checkout 后 git status 无该文件;git diff 对该路径为空。后续约束
eol=lf 后出现「永远 M 的文本文件」,优先核对 git diff 是否仅为 CRLF↔LF 与 git add --renormalize,不要先大范围改业务代码;批量合并子分支进主干前确认提交信息符合本仓库 Conventional Commits 规则。packages/vue-element-cui-nuxt 的 dev warning 清理经验历史现象
nuxt dev 里仍可能残留 i18n、OG Image、Icon、Sass 等 warning。实际根因
defaultLocale、同名 composables 与自动导入叠加、未启用却仍调用 defineOgImageComponent()、缺失本地 lucide 集合、样式仍使用全局 mix()。有效修复
ogImage.enabled = false 时应通过页面覆盖去掉 defineOgImageComponent() 调用,而不是硬开模块;安装 @iconify-json/lucide;把 Sass 的 mix() 迁移到 color.mix()。记忆重点
后续约束
fresh dev.stderr 是否为空、页面 HTTP 是否 200、Chrome console 是否无新增 warn/error。packages/vue-element-cui-nuxt 的 Windows PowerShell 构建假卡死与 Nitro trace 事故(2026-03)问题现象
pnpm --filter @eams-monorepo/vue-element-cui-nuxt build 长期停在 Building Nuxt Nitro server (preset: node-server);多次超时重跑后,看起来像是“越跑越卡、彻底卡死”。实际根因
externals.trace 会触发 nodeFileTrace,在当前文档站 + pnpm workspace + Windows 环境下持续消耗高 CPU 和高内存,构建长时间卡在 Nitro 收尾。第二层是假象放大:PowerShell 下超时终止、手动中断,或 Start-Process 后台运行 pnpm -> cmd -> node -> nuxt build 时,外层命令结束不代表内层子进程树退出,旧构建链会残留并和新构建叠加。关键误导点
Get-Process、日志和产物观察会把旧进程噪音误判成当前命令的状态。关键线索
.nuxt/dist/server/server.mjs 已生成,但 .output/server 仍为空,说明 Vite SSR 已完成、卡点在 Nitro 收尾;同时 nuxt.mjs build 的工作集可涨到 2GB 以上,CPU 仍持续增加,符合 nitropack 的 nodeFileTrace tracing 阶段特征。有效修复
pnpm -> cmd -> node 构建链,只保留一条单独进程复现;然后在 packages/vue-element-cui-nuxt/nuxt.config.ts 中显式设置 nitro.externals.inline = [/.*/](而非 trace = false),让 Rollup 把全部依赖内联进 server bundle,同时绕开 Windows + pnpm workspace 下 @vercel/nft tracing 的卡死问题。验证方式
pnpm --filter @eams-monorepo/vue-element-cui-nuxt exec nuxi build --logLevel=verbose,应生成 .output/server/index.mjs 并打印 Build complete!;同时确认不再残留目标构建进程链。后续约束
nitro.externals.trace = false——它虽然能绕开 tracing 卡死,但会导致 Vercel 云函数产物缺失 node_modules 和 package.json,运行时直接报错(参见下方「Vercel 云函数依赖缺失事故」)。正确的绕行方式是 externals.inline = [/.*/],让依赖内联进 bundle 而非依赖外部 node_modules。packages/vue-element-cui-nuxt 的 Vercel 云函数 entities/decode 崩溃事故(多版本依赖 + Nitro externals 连环踩坑,2026-04)问题现象
500 FUNCTION_INVOCATION_FAILED,运行时日志统一报 Cannot find module 'entities/decode',require stack 指向 /var/task/node_modules/@vue/compiler-core/dist/compiler-core.cjs.prod.js。实际根因(两层叠加)
nuxt.config.ts 中 nitro.externals.trace = false 关闭了 @vercel/nft(Node File Trace),导致构建产物 __fallback.func/ 完全不含 node_modules 和 package.json,云函数在运行时找不到任何外部依赖。entities(4.5.0 via svgo、6.0.1 via parse5、7.0.1 via @vue/compiler-core@3.5.30)。@vue/compiler-core 的 CJS 生产构建在运行时做 require('entities/decode'),需要 entities@7.x 的 ./decode 子路径导出。当 Nitro 的 @vercel/nft 追踪依赖时,可能追踪到错误版本(4.x 或 6.x),或者 Vercel 从函数的 package.json 安装依赖时拉到了错误版本,导致 entities/decode 在运行时不可用。关键误导点与踩坑路径
trace: false 就能修复。但即使移除后,Vercel 在 Linux 上构建时,Nitro 的默认 trace 仍然没有正确包含 entities@7.x(因为多版本共存,trace 可能选错版本)。externals.inline = [/.*/] 在本地 Windows 构建能生成自包含 bundle("dependencies": {}),看起来修好了。但 Vercel 构建框架在 Nitro 之后会再跑一次自己的 @vercel/nft,检测到 bundle 中残留的 require() 引用后,从项目 node_modules 重新拷贝了不完整的 Vue 运行时(缺少正确版本的 entities),导致运行时同样报错。node_modules 结构不同,turbo cache 行为不同,@vercel/nft 追踪结果也不同。本地验收不能替代 Vercel 实际部署验证。有效修复(两步组合)
nuxt.config.ts 中所有 nitro.externals 配置,让 Nitro 使用默认的 @vercel/nft trace 行为(Vercel 在 Linux 上构建,不存在 Windows 的 trace 卡死问题)。entities 加为 packages/vue-element-cui-nuxt/package.json 的显式 dependencies("entities": "^7.0.1"),并在 pnpm-workspace.yaml 的 overrides 中添加 entities: "^7.0.1",强制整个 workspace 统一使用 7.x 版本,消除多版本歧义。验证方式
211c662 后,https://vec.ruan-cat.com/ 不再返回 FUNCTION_INVOCATION_FAILED,而是返回 Nuxt 应用层的 JSON 错误响应({"statusCode": 500, "statusMessage": "Server Error"})——证明云函数已正常启动,entities/decode 模块可用;Nuxt Content API(如 /api/_content/query)正常响应 404(内容未找到)而非模块缺失崩溃。后续约束
nitro.externals.trace = false。它会让 Vercel/Netlify 等 serverless 平台的云函数在运行时找不到依赖。nitro.externals.inline = [/.*/] 来修复 Vercel 部署。它在本地能工作,但 Vercel 构建框架会在 Nitro 之后再跑一次 @vercel/nft,重新引入不完整的 node_modules。pnpm-workspace.yaml 的 overrides 统一锁定,尤其是被运行时 CJS require() 子路径导出依赖的包(如 entities)。node_modules 结构、缓存行为都可能不同,必须通过 Vercel MCP 或直接访问部署 URL 确认运行时状态。FUNCTION_INVOCATION_FAILED(模块缺失/函数崩溃)vs Nuxt JSON 错误响应(应用层 SSR 错误),两者排查路径完全不同。@vueuse/core 模块缺失事故——workspace 包 + Vite SSR 外部化连环踩坑(2026-04)问题现象
ERR_MODULE_NOT_FOUND: Cannot find package '@vueuse/core' imported from /var/task/node_modules/element-plus/es/hooks/use-calc-input-width/index.mjs,云函数崩溃返回 500。实际根因(三层叠加)
node_modules 中的包标记为 external,包括 workspace 包 @eams-monorepo/vue-element-cui 和 element-plus。这意味着运行时需要从 node_modules 加载它们。@eams-monorepo/vue-element-cui(通过 workspace:* 引入)的编译产物 dist/index.js 中有 import ... from 'element-plus',element-plus 的 ESM 文件又 import ... from '@vueuse/core'。完整链路:Nuxt SSR → workspace 包(external)→ element-plus(external)→ @vueuse/core(缺失)。@vueuse/core 在 workspace 中有 3 个版本(v12/v13/v14),pnpm 的符号链接结构导致 @vercel/nft 追踪不到正确版本,@vueuse/core 未被包含在云函数的 node_modules 中。关键误导点与踩坑路径
nitro.externals.inline 能解决问题。实际上 Nitro 的 inline 作用于 Nitro Rollup 阶段,但 Vite SSR 在更早阶段就已经将这些包外部化了,Nitro 拿到的是已外部化的 import 语句,inline 配置来不及介入。@vueuse/core 为直接依赖就行。但有 3 个大版本(v12/v13/v14),override 到单一版本可能破坏兼容性(element-plus 需要 v12,shadcn-docs-nuxt 需要 v14)。node_modules,Vite 默认将其外部化。其内部对 element-plus 的 import 在运行时从 workspace 包的目录上下文解析,而非从 Nuxt app 的目录解析。有效修复
nuxt.config.ts 的 vite.ssr.noExternal 中列出 workspace 包及 element-plus 完整运行时依赖树,阻止 Vite SSR 将它们外部化,强制在构建时打入 server bundle:
vite: {
ssr: {
noExternal: [
"@eams-monorepo/vue-element-cui", // workspace 包
/element-plus/, /@element-plus/, /@vueuse/, /vue-demi/,
/@ctrl\/tinycolor/, /@floating-ui/, /@popperjs\/core/,
/async-validator/, /escape-html/, /lodash-unified/, /lodash-es/,
/memoize-one/, /normalize-wheel-es/, /entities/,
],
},
}
isWindows(来自 std-env)条件性地在 Windows 本地构建时跳过 NFT trace(避免卡死),Vercel Linux 构建正常 trace。验证方式
element-plus 代码出现在 __fallback.func/chunks/ 的 server chunks 中(而非 node_modules),bundle 大小从 5.87 MB 增长到 8.38 MB。https://vec.ruan-cat.com/ 返回 HTTP 200(而非之前的 500 崩溃),/api/_content/navigation 正常响应(不再报 ERR_MODULE_NOT_FOUND)。后续约束
vite.ssr.noExternal,而非 nitro.externals.inline。两者作用于不同阶段(Vite SSR 构建 vs Nitro Rollup),前者是根本修复点。workspace:*)在 SSR 场景下必须加入 noExternal,否则运行时通过符号链接加载会丢失依赖上下文。noExternal 条目时,需列出目标包的完整运行时依赖树(如 element-plus → @vueuse/core → @vueuse/shared),遗漏任何一个传递依赖都可能导致新的 ERR_MODULE_NOT_FOUND。std-env 等非 Node.js 内置包时,必须在当前子包的 package.json 中显式声明,避免幽灵依赖。范围:packages/vue-element-cui-nuxt(组件库文档站)
时间:2026-04
关键词:pnpm monorepo、Vercel serverless、Nitro、Vite SSR、@vercel/nft、预渲染、document-driven、workspace 包、多版本依赖
这是一个由 Windows 本地构建优化引发、在 Vercel Linux 生产环境暴露的连锁崩溃。最初为了解决 Windows 本地 @vercel/nft trace 卡死而添加的 nitro.externals.trace = false 和 prerender:routes 清空钩子,在后续几个月里持续影响 Vercel 部署,最终导致三层叠加的故障:
| 层级 | 现象 | 根因 |
|---|---|---|
| 第一层 | FUNCTION_INVOCATION_FAILED,Cannot find module 'entities/decode' | trace: false 导致云函数缺失 node_modules;后续 entities 多版本歧义 |
| 第二层 | ERR_MODULE_NOT_FOUND: Cannot find package '@vueuse/core' | element-plus 被 Vite SSR 外部化,workspace 包导入链 + pnpm 符号链接导致 NFT 追踪失败 |
| 第三层 | TypeError: Cannot read properties of null (reading '_id') | prerender:routes 清空钩子禁用了预渲染,document-driven 的 Nuxt Content 无法在构建时解析 markdown 为结构化对象,运行时 content 数据库为空 |
不要用「本地能跑」的补丁去解决生产环境问题。 Windows 和 Linux 的 node_modules 结构、@vercel/nft 行为、预渲染流程完全不同。为 Windows 添加的每一个 workaround 都可能在 Linux 上制造新问题:
| Windows 补丁 | 解决的本地问题 | 引发的生产问题 |
|---|---|---|
nitro.externals.trace = false | NFT trace 卡死 | 云函数完全缺失 node_modules |
nitro.externals.inline = [/.*/] | 绕开 trace 卡死 | Vercel 二次 NFT 追踪引入残缺 node_modules |
prerender: { crawlLinks: false } + routes.clear() | 减少构建时间 | Content 文档未被预解析,运行时数据库为空 |
vite.ssr.noExternal:将 workspace 包 @eams-monorepo/vue-element-cui 及 element-plus 完整依赖树加入 noExternal,阻止 Vite SSR 外部化,在构建时打入 server bundle。nitro.externals.inline:保留精准 inline 列表作为补充(与 ssr.noExternal 互为保险)。isWindows ? { trace: false } : {}:用 std-env 检测平台,仅 Windows 本地跳过 NFT trace,Vercel Linux 正常 trace。prerender: { crawlLinks: true }:恢复预渲染,让 document-driven 的 Nuxt Content 在构建时解析 markdown 为结构化对象。pnpm-workspace.yaml overrides:锁定 entities: "^7.0.1" 消除多版本歧义。entities、std-env 等包显式加入子包 package.json,杜绝幽灵依赖。trace: false 或 inline: [/.*/],必须通过平台检测条件化。routes.clear()),document-driven 的 Nuxt Content 依赖预渲染阶段解析 content。vite.ssr.noExternal。范围:eams-frontend-monorepo/scripts
时间:2026-03
关键词:UTF-8 BOM、管道误用、git 钩子、stderr、$LASTEXITCODE、--no-ff
假语法错误
.ps1 在 Windows PowerShell 5 下报「字符串缺少终止符」「意外标记 }」等,实为编码解析问题,非逻辑写错。误报「冲突」与 merge --abort 失败
git merge origin/f1 实际已成功,脚本却进入 catch,提示「冲突或失败」。ℹ 输出 N 个暂存区文件路径、ANSI 颜色码。git merge --abort 报 fatal: There is no merge to abort,因 MERGE_HEAD 已不存在。推送节奏误解
push 还是每步 push。历史图异常膨胀
git merge --no-ff,即使能快进也会强制新增合并节点。编码与 PS5
$ErrorActionPreference、管道与钩子 stderr
$ErrorActionPreference = "Stop" 与 git merge ... 2>&1 | ForEach-Object { ... } 叠加使用。stderr 并入后,PowerShell 易将 native 的 stderr 当成终止错误,直接进入 catch;此时合并已结束,MERGE_HEAD 已清除,merge --abort 无合并可中止。管道与退出码
$LASTEXITCODE 在管道后不能可靠代表 git merge 本身,与 git push 同理。合并策略配置不当
--no-ff,属于策略滥用。catch 里的文字当成真实合并冲突。merge --abort 的 fatal 当成仓库损坏。MERGE_HEAD 是否存在、是否已产生合并提交;若合并已成功,多为误报。脚本编码
调用 git 的方式
git merge / git push。git ...,再用 if ($LASTEXITCODE -ne 0) 判断成败。远程更新节奏
merge-all-branches-to-f1.ps1 里每次合并成功后执行 git push origin f1。merge-f1-to-all-branches.ps1「每子分支合并后即 push」的策略对齐。合并策略回归默认
--no-ff,恢复 git merge --no-edit 默认行为。Parser::ParseFile 对 .ps1 无语法错误。git push。git status 无意外冲突状态。编码与 git 调用
git merge / git push 使用 2>&1 | 管道;与脚本内「push 无管道」注释一致。stderr 文案,优先怀疑 Stop + 管道,而非真实合并失败。--no-ff;若业务明确要求「绝不新增合并节点」,应改为 --ff-only 并接受失败即中止。经验落点
.cursor/skills 另立平行 SKILL,应把事故模式合并进本技能的仓库级经验库。packages/vue-element-cui 的 CuiDialog 弹层遮罩完全失效事故(Element Plus appendToBody 默认值变更 + CSS 堆叠上下文,2026-04)问题现象
实际根因(两层叠加)
appendToBody 属性类型改为 Boolean(无显式默认值),Vue 3 中 Boolean prop 未传时默认 false。源码中 ElTeleport 的 disabled 计算为 !appendToBody,即 !false = true,导致 <Teleport to="body"> 被禁用。overlay 不再挂载到 <body>,而是留在组件所在的 DOM 层级中。.cui-demo-container 设有 isolation: isolate(用于样式隔离),创建了新的堆叠上下文。overlay 虽然是 position: fixed 且 z-index: 2002,但它的 z-index 只在 .cui-demo-container 的堆叠上下文内生效,无法覆盖页面上层的 header(z-index: 40)、sidebar(z-index: 30)等元素。关键误导点
nuxt.config.ts 中 vite.ssr.noExternal 的依赖外部化配置过激导致 CSS 丢失。实际检查生产 CSS 文件(367KB)后确认 Element Plus 全部样式类(.el-dialog、.el-overlay、.el-button)、CSS 变量(--el-color-primary、--el-overlay-color-lighter)均存在且完整。@layer base preflight 重置覆盖了 Element Plus 样式。实际上 Element Plus CSS 是非分层(unlayered)样式,在 CSS 级联中始终优先于 @layer base 中的规则。getComputedStyle 检查 overlay 时,所有属性看起来完全正确(background-color: rgba(0,0,0,0.5)、position: fixed、inset: 0px、z-index: 2002),但页面视觉上没有遮罩效果。关键转折点是检查 overlay.parentElement 发现其父节点是 DIV.space-y-4(demo 组件内部)而不是 BODY,然后追溯祖先链找到了 isolation: isolate。有效修复
CuiDialog 组件的 <el-dialog> 上添加 append-to-body 属性,强制启用 Teleport 将 overlay 挂载到 <body> 层级,绕过 .cui-demo-container 的堆叠上下文限制。验证方式
document.querySelector('.el-overlay').parentElement === document.body 返回 true,确认 overlay 已挂载到 body。document.elementFromPoint() 在页面各位置(header、sidebar、content、corner)均返回 el-overlay-dialog,确认遮罩覆盖全页面。后续约束
appendToBody/teleported 默认值在不同大版本间有变化(旧版 teleported 默认 true,新版 appendToBody 默认 false),升级后如果弹层不显示遮罩,优先检查此项。isolation: isolate 创建堆叠上下文时,必须同时确保内部的弹层组件开启了 Teleport,否则 overlay 的 z-index 会被困在该上下文内。overlay.parentElement 是否为 body,而不是检查 CSS 属性值。CSS 属性全部正确但 overlay 不可见的最常见原因是 Teleport 失效 + 堆叠上下文。如果这次 bug 与仓库已有事故模式相似,写记忆时不要遗漏下面这些额外信息:
extends: ["shadcn-docs-nuxt"]未来写事故记录时,优先记录可重复验证的证据,而不是模糊措辞。
fresh dev.stderr 为空/components 返回 200Chrome console 无新的 warn/error把根级 AI 记忆经验吸收到技能里,不等于把技能写成修复手册。下面这些内容不应该成为这个技能的主体:
这个技能只负责记忆沉淀和总结。
它不能替代调试、实现、测试和修复工作流。如果 bug 还没修好,先使用合适的调试或实现技能,等结果稳定后再回到这个技能做经验沉淀。
问题现象
实际根因
关键误导点
有效修复
验证方式
后续约束
main.ts、sample 页面、组件 README、组件入口文件里接入工具或调整结构时,不要再用覆盖式重写替代局部修改;不要删减掉注释,不要损耗原本的组件传达的信息。问题现象
packages/vue-element-cui-nuxt/nuxt.config.ts 中直接 import { isWindows } from "std-env",但 packages/vue-element-cui-nuxt/package.json 没有声明 std-env 为依赖。本地因为 .npmrc 的 shamefully-hoist=true 将 std-env(Nuxt 的传递依赖)提升到了根 node_modules,代码可以正常 resolve,但这属于典型的幽灵依赖。实际根因
import { platform } from "node:os" 为 std-env 时,只确认了"Nuxt 生态已经内置 std-env"就直接使用,没有检查当前 package.json 是否显式声明了该依赖。在 pnpm 严格模式或其他包管理器下,这种幽灵依赖会直接导致 ERR_MODULE_NOT_FOUND。关键误导点
shamefully-hoist=true 掩盖了幽灵依赖问题,本地开发一切正常,但部署或其他环境可能失败。有效修复
packages/vue-element-cui-nuxt/package.json 的 dependencies 中显式添加 "std-env": "^3.10.0"。验证方式
pnpm why std-env 确认依赖链正确;检查 package.json 确认显式声明存在。后续约束
package.json 中显式声明,不论它是否被上层依赖间接安装。即使是 Nuxt、Nitro、Vite 等框架的已知内部依赖(如 std-env、pathe、defu、consola 等),也不能跳过显式声明直接使用。node:os、node:path),优先使用内置模块,避免引入不必要的外部依赖。