You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SvelteKit应用错误堆栈追踪行号不正确的原因及解决方法

手动创建Error时堆栈行号异常的原因及解决方法

问题场景

通过以下命令创建SvelteKit项目骨架:

npm create svelte@latest lineno
cd lineno
npm install

创建src/hooks.server.js脚本,代码如下:

export const handle = async ({ event, resolve }) => {
  console.log(new Error("My error").stack)
  return await resolve(event);
}

执行后打印的错误堆栈显示行号为4,但实际创建Error的代码明明在第2行:

Error: My error
    at Object.handle (/erikor/Documents/Business/lineno/src/hooks.server.js:4:15)

有意思的是,代码里自动抛出的运行时错误(比如直接写throw new Error('test'))却能显示正确的源码行号。

原因分析

这是因为SvelteKit在开发或构建阶段会对代码做转译处理——比如给异步函数添加辅助逻辑、做语法降级、注入框架相关代码等,最终运行的代码和你写的源码结构、行号都不一样。

手动创建Error时,堆栈信息是基于转译后的代码生成的;而运行时自动抛出的错误,SvelteKit(或其底层的Vite/Rollup)会通过sourcemap自动把转译后的行号映射回源码行号,但手动打印Error.stack时,默认不会触发这个映射逻辑。

解决方法

1. 开发环境快速解决:开启Node.js的sourcemap支持

启动项目时添加--enable-source-maps参数,让Node.js自动根据sourcemap转换行号:

node --enable-source-maps node_modules/@sveltejs/kit/dist/cli.js dev

也可以直接修改package.json里的dev脚本,以后启动不用每次加参数:

{
  "scripts": {
    "dev": "node --enable-source-maps node_modules/@sveltejs/kit/dist/cli.js dev"
  }
}

这样手动打印的Error.stack就会显示源码里的正确行号了。

2. 生产环境:手动解析sourcemap

如果是生产环境,需要借助source-map包手动转换堆栈行号:

  • 先安装依赖:
npm install source-map
  • 编写工具函数处理堆栈:
import { SourceMapConsumer } from 'source-map';
import fs from 'fs';
import path from 'path';

async function fixErrorStack(error) {
  const stack = error.stack;
  // 生产环境的sourcemap路径根据实际构建输出调整
  const sourceMapPath = path.join(process.cwd(), '.svelte-kit/output/server/hooks.server.js.map');

  if (!fs.existsSync(sourceMapPath)) return stack;

  const rawSourceMap = JSON.parse(fs.readFileSync(sourceMapPath, 'utf8'));
  const consumer = await new SourceMapConsumer(rawSourceMap);

  const correctedStackLines = stack.split('\n').map(line => {
    const match = line.match(/at .+ \((.+):(\d+):(\d+)\)/);
    if (!match) return line;

    const [, filePath, lineNum, colNum] = match;
    if (!filePath.includes('hooks.server.js')) return line;

    const originalPos = consumer.originalPositionFor({
      line: parseInt(lineNum),
      column: parseInt(colNum)
    });

    if (originalPos.source) {
      return line.replace(
        `${filePath}:${lineNum}:${colNum}`,
        `${path.basename(originalPos.source)}:${originalPos.line}:${originalPos.column}`
      );
    }
    return line;
  });

  consumer.destroy();
  return correctedStackLines.join('\n');
}

// 使用示例
export const handle = async ({ event, resolve }) => {
  const error = new Error("My error");
  const correctedStack = await fixErrorStack(error);
  console.log(correctedStack);
  return await resolve(event);
}

内容的提问来源于stack exchange,提问作者ejkreboot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 06:55:57