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

如何在Vite中获取经Source Map映射后的URL?

最简方式在Vite中实现编译后URL到源码URL的映射(适配console.log跳转)

核心思路

  • 利用Vite开发环境默认生成的Source Map,通过source-map库解析编译后的行列,映射回源码位置
  • 重写console.log时,提取错误栈中的编译后位置,加载对应Source Map完成映射,拼接带行列的__open-in-editor跳转链接

步骤1:安装依赖

因为需要在浏览器端解析Source Map,安装官方的source-map库:

npm install source-map --save-dev

步骤2:实现映射逻辑(无需Vite插件)

在项目入口文件(如src/main.js或Svelte组件的onMount钩子)中添加以下代码:

import { SourceMapConsumer } from 'source-map';

// 保存原始console.log
window._log = console.log.bind(console);
// 缓存已加载的Source Map,避免重复请求
const sourceMapCache = new Map();

// 重写console.log
console.log = async function (...args) {
  try {
    // 抛出错误获取调用栈
    throw new Error('get call stack');
  } catch (err) {
    const stackLine = err.stack?.split('\n')[1];
    if (!stackLine) {
      window._log(...args);
      return;
    }

    // 提取编译后的URL、行、列
    const [, compiledUrl] = stackLine.split('@');
    if (!compiledUrl) {
      window._log(...args);
      return;
    }

    const [compiledPath, compiledLineStr, compiledColumnStr] = compiledUrl.split(':');
    const compiledLine = parseInt(compiledLineStr, 10);
    const compiledColumn = parseInt(compiledColumnStr, 10);

    // 加载并解析Source Map
    let consumer;
    if (sourceMapCache.has(compiledPath)) {
      consumer = sourceMapCache.get(compiledPath);
    } else {
      try {
        const smResponse = await fetch(`${compiledPath}.map`);
        const sourceMapData = await smResponse.json();
        consumer = await new SourceMapConsumer(sourceMapData);
        sourceMapCache.set(compiledPath, consumer);
      } catch (e) {
        // Source Map加载失败,输出无行列的跳转链接
        const relativePath = compiledPath.replace(location.origin + '/', '');
        const openLink = `${location.origin}/__open-in-editor?file=${encodeURIComponent(relativePath)}`;
        window._log(...args, openLink);
        return;
      }
    }

    // 映射到源码位置
    const sourceMapping = consumer.originalPositionFor({
      line: compiledLine,
      column: compiledColumn
    });

    if (sourceMapping.source) {
      // 处理源码路径,转换为项目根相对路径
      let sourcePath = sourceMapping.source;
      if (!sourcePath.startsWith('/')) {
        const projectRoot = compiledPath.split('/src')[0];
        sourcePath = `${projectRoot}/${sourcePath}`;
      }
      const relativePath = sourcePath.replace(location.origin + '/', '');
      // 拼接带行列的跳转链接
      const openLink = `${location.origin}/__open-in-editor?file=${encodeURIComponent(relativePath)}&line=${sourceMapping.line}&column=${sourceMapping.column || 1}`;
      window._log(...args, openLink);
    } else {
      // 无映射结果,输出原始路径链接
      const relativePath = compiledPath.replace(location.origin + '/', '');
      const openLink = `${location.origin}/__open-in-editor?file=${encodeURIComponent(relativePath)}`;
      window._log(...args, openLink);
    }
  } catch (e) {
    // 任何异常都回退到原始console.log
    window._log(...args);
  }
};

关键说明

  • 无需编写Vite插件:纯前端代码即可实现,适合快速测试需求
  • Source Map缓存:避免重复请求同一个文件的Source Map,提升性能
  • 兼容场景:开发环境默认生效(Vite默认生成Source Map),生产环境若关闭Source Map会自动回退到无行列的链接
  • 跳转支持:__open-in-editor链接支持直接跳转VSCode(需系统已安装并配置默认编辑器),解决Firefox无法直接跳转的问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 20:24:32