如何排查CD环节的问题
问题描述
排查步骤
针对本地不可重现的问题
第一步:提供日志
先得输出日志,明确错误原因。 修改内容:脚本中从exec改为spawn了。
到这一步,就能看到报错信息了:
[ ERROR ] Rollup: Missing Export
@stencil/core/internal/app-globals (1:7): "default" is not exported
by "src/global/global.ts", imported by
"@stencil/core/internal/app-globals". 1: import appGlobalScript from
'/drone/src/packages/paradigm-hivis/src/global/global.ts'; ^ 2:
export const globalScripts = appGlobalScript; 3: export const
globalStyles = "@unocss preflights; @unocss default; @unocss
variants; :root{--viz-primary:#165Dff;--viz...
查看stencil/core的源码:
const appendGlobalScripts = (globalScripts: GlobalScript[], s: MagicString) => {
if (globalScripts.length === 1) {
s.prepend(`import appGlobalScript from '${globalScripts[0].path}';\n`);
s.append(`export const globalScripts = appGlobalScript;\n`);
} else if (globalScripts.length > 1) {
globalScripts.forEach((globalScript) => {
s.prepend(`import ${globalScript.defaultName} from '${globalScript.path}';\n`);
});
s.append(`export const globalScripts = () => {\n`);
s.append(` return Promise.all([\n`);
globalScripts.forEach((globalScript) => {
s.append(` ${globalScript.defaultName}(),\n`);
});
s.append(` ]);\n`);
s.append(`};\n`);
} else {
s.append(`export const globalScripts = () => {};\n`);
}
};
发现是6年前就有的,那就说不过去了。
这个其实比较奇怪,我们外网本地、内网本地都没问题,只有CI/CD跑的环境才有问题。 二者的差异就只剩系统(CentOS、Windows)了,难道是系统的原因么?
第二步:大胆假设
- node版本:nvm切换测试
- 镜像:修改CI/CD的镜像
- 依赖包版本未固定导致的依赖升级问题:确认依赖版本是否锁定
第三步:去掉错误答案
根据逻辑分析,把一些明显不对的猜测给去掉。
比如依赖包版本未固定导致的依赖升级问题,这个从逻辑上就说不通,内网本地是OK的,如果是这个原因,应该内外网都会出问题才对。
第四步:逐个求证
对经过分析和筛选后,仍然不能排除的猜测,逐个进行验证。
AI分析
最可能的根本原因是:
🎯 根本原因:TypeScript + Rollup 模块解析的环境差异
- 关键发现:
从错误信息可以看出: @stencil/core/internal/app-globals (1:7): “default” is not exported by “src/global/global.ts”
这说明 Stencil 的内部模块系统正在尝试导入 global.ts 的默认导出。
- 为什么本地能工作?
本地环境的可能”宽容”因素:
-
编译缓存差异: - 本地可能有 node_modules/.cache 或 .stencil 缓存 - 缓存中可能存在”宽容”编译的版本
-
TypeScript 编译器版本/配置差异: - 虽然你设置了 Node.js 18.16.0,但 TypeScript 版本可能不同 - allowSyntheticDefaultImports 可能在本地环境中”工作”得更好
-
构建顺序差异: - 本地构建可能有不同的文件处理顺序 - 某些情况下,Rollup 可能没有严格检查默认导出
-
为什么 CI/CD 失败?
CI/CD 环境的”严格”因素:
-
干净构建: - 每次都是全新的构建环境 - 没有缓存干扰,严格按照配置执行
-
Stencil 内部机制: - Stencil 的 app-globals 模块期望全局脚本有默认导出 - 在干净环境中,这个期望被严格执行
-
Rollup 严格模式: - 生产构建时,Rollup 更严格地检查 ES 模块规范 - 没有默认导出时直接报错而不是警告
-
为什么添加 export default 能解决问题?
Stencil 全局脚本的预期结构:
根据 Stencil 文档,全局脚本文件应该:
- 执行全局初始化代码
- 导出一个默认导出(可以是对象、函数或 undefined)
你的文件结构分析:
// 你的 global.ts 有: export const globalUtils = { … }; export const GLOBAL_CONFIG = { … };
// 但缺少: export default globalUtils; // ← 这是 Stencil 期望的
🔧 解决方案验证
让我验证一下这个修复是否正确:
⏺ Bash(grep -A 5 -B 5 “export default” src/global/global.ts) ⎿ // Compatibility: also mount to global scope (globalThis as any).HIVIS = globalUtils; } … +3 lines (ctrl+r to expand)
⏺ 📋 总结:根本原因
问题的核心:
- Stencil 全局脚本机制:Stencil 的内部系统期望全局脚本文件有一个默认导出
- 环境差异:本地环境的某种”宽容”让缺少默认导出的代码也能工作
- CI/CD 严格性:干净构建环境中,Stencil 严格执行其内部要求
本地能工作的可能原因:
- 缓存效应:本地缓存可能包含之前构建的”宽容”版本
- 构建工具链版本差异:虽然 Node.js 版本相同,但相关工具版本可能不同
- 文件系统/时间戳差异:本地构建可能跳过了某些检查
添加 export default 解决问题的原因:
这满足了 Stencil 内部 app-globals 模块的期望,使其在所有环境中都能正确导入全局脚本。
教训:Stencil 全局脚本文件必须有一个默认导出,即使它只是 export default undefined。
结论
我感觉还是没有锁定版本的缘故导致的。因为同样的代码,之前没报这个问题,现在不正常,大概率是中间某个依赖升级了,导致这个问题出现了。 时间问题,我没去查看源码深究,只是猜测。
反思
环境问题
构建环境,重现问题,永远是最优先的事情。 这次内网无法拉取镜像,就导致我们耗费了很多精力去猜测和尝试。问题解决后,我马上联系了运维同学,把内网如何拉取我们需要的镜像这个问题给解决了。