现象
Directus extensions 打印错误日志,只能打印出 javascript 堆栈,无法打印出 typescript 堆栈。
排查过程
- 检查了输出目录 dist,发现 dist 目录下有对应的 map 文件,说明 rollup 打包确实生成了 map 文件。
- 检查项目,确实安装了 source-map-support,而且在入口文件中引入了 source-map-support/register。
- 进一步检查 map 文件, map 文件中确实包含了 typescript 的堆栈信息。
- 分析打印出来的堆栈信息,发现堆栈信息中的路径后面带了一个时间戳参数,导致 source-map-support 无法正确解析到源文件。
[ERROR] directus-extension-FX - setup error Error: mock error
at Object.setup (file:///Users/marsyas/Documents/Development/Projects/fx-engine/extensions/directus-extension-FX/dist/api.js?t=1729783263163:1:311160)
at EventEmitter.<anonymous> (file:///Users/marsyas/Documents/Development/Projects/fx-engine/extensions/directus-extension-FX/dist/api.js?t=1729783263163:1:312108)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at async Promise.all (index 0)
at Emitter.emitInit (file:///Users/marsyas/Documents/Development/Projects/fx-engine/node_modules/.pnpm/@directus+api@13.0.0/node_modules/@directus/api/dist/emitter.js:55:13)
解决方案
重写 source-map-support 的 retrieveFile 方法,去掉文件路径中的时间戳参数即可。
sourceMapSupport.install({
retrieveFile: function (path) {
path = path.trim();
path = path.replace(/\?t=\d+/, "");
if (/^file:/.test(path)) {
path = path.replace(/file:\/\/\/(\w:)?/, function (protocol, drive) {
return drive
? ""
: "/";
});
}
if (path in fileContentsCache) {
return fileContentsCache[path];
}
var contents = "";
try {
if (!fs) {
var xhr = new XMLHttpRequest();
xhr.open("GET", path, false);
xhr.send(null);
if (xhr.readyState === 4 && xhr.status === 200) {
contents = xhr.responseText;
}
} else if (fs.existsSync(path)) {
contents = fs.readFileSync(path, "utf8");
}
} catch (er) {
}
return (fileContentsCache[path] = contents);
},
});
重新打印错误日志,即可看到正确的 typescript 堆栈信息:
[ERROR] directus-extension-FX - setup error Error: mock error
at Object.setup (file:///Users/marsyas/Documents/Development/Projects/fx-engine/extensions/directus-extension-FX/src/mock/index.ts:32:11)
at EventEmitter.<anonymous> (file:///Users/marsyas/Documents/Development/Projects/fx-engine/extensions/directus-extension-FX/src/hooks/init/index.ts:53:18)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at async Promise.all (index 0)
at Emitter.emitInit (file:///Users/marsyas/Documents/Development/Projects/fx-engine/node_modules/.pnpm/@directus+api@13.0.0/node_modules/@directus/api/dist/emitter.js:55:13)
原因
继续追踪directus源码,发现在加载extensions时,为了支持热更新,使用了Cache Break技术,也就是会在路径后面加上时间戳参数,比如:
//api/src/extensions.ts
const endpointInstance: EndpointConfig | { default: EndpointConfig } = await import(
`./${pathToRelativeUrl(endpointPath, __dirname)}?t=${Date.now()}`
);
这样导致source-map导致找不到对应文件,因而直接抛出了js错误堆栈。