网站搜索

javascript - 如何通过 console.log 使用自定义 URL 打开浏览器调试器


我有一个脚本用于添加和/或修改日志到控制台的数据,我们称它为 logger.js,可以像 logger.warn(data) 这样调用它。

在控制台查看的所有日志都会打印它们的来源,如 logger.js:123:45,而不是实际的来源。为了解决这个问题,我正在解析跟踪以找到实际的来源,并将其也记录到控制台中。点击时会打开正确的文件/位置,但在一个单独的浏览器标签页中。

是否可以在控制台调试工具中打开这个 URL?如果可以,该如何操作?

答案#1

使用 强制 源映射

我最近遇到了类似的需求,并意识到我可以为此使用源映射。这一想法受到了这个看似无关的问题的很大启发。

所以,我们想要一个可点击的链接,能够

  • 指向我们的文件
  • 并指出正确的行号

而且我们知道该文件的 URL 和行号。我们也知道要抛出什么错误。

为了到那里,我们

  1. 创建一个包含单个 throw 语句的虚拟文件
  2. 附加一个真正指向我们文件的源映射
  3. 对生成的代码使用 eval
  4. 在浏览器控制台中惊叹于结果

<script type="module">
import {encode} from 'https://cdn.jsdelivr.net/npm/[email /+esm'

throwClickableError(new Error("Here is the error that points at a Markdown file. Isn't this magic?"), {
  url: "https://cdn.jsdelivr.net/npm/[email /LICENSE.md",
  text: null,
  line: 16,
  column: 3,
});

/**
 * @typedef ErrorLocation
 * @prop {string} url URL to point at
 * @prop {string | null} text Source code to point at
 * @prop {number} line Line number to point at (1-based)
 * @prop {number} column Column to point at (1-based)
 */

/**
 *
 * @param {Error} error
 * @param {ErrorLocation} source
 */
export function throwClickableError(error, source) {
  // We remap an error directly to where we need it to be
  // The fields are
  // 1. Generated column (aka 0)
  // 2. Index into sources list (aka 0)
  // 3. Original line number (zero based)
  // 4. Original column number (zero based)
  // Limitations:
  // - In Firefox, errors will point at the line where they happened.
  // - In Chrome, errors will start at the correct column, but will go until the end of the line
  let mappings = encode([
    0,
    0,
    Math.max(0, source.line - 1),
    Math.max(0, source.column - 1),
  ]);

  const sourceMap = {
    version: 3,
    file: null,
    sources: [source.url],
    sourcesContent: [source.text],
    names: [],
    mappings,
  };
  const encodedSourceMap = btoa(
    unescape(encodeURIComponent(JSON.stringify(sourceMap))),
  );

  // Only display the error message once
  let message = error.message;
  error.message = undefined;

  let generatedCode = `(err, message) => { throw new Error(message, {cause:err}); }
//# sourceMappingURL=data:application/json;base64,${encodedSourceMap}
//# sourceURL=${source.url}`;

  // Shrink the stack trace on Chrome
  let oldLimit = 0;
  if ("stackTraceLimit" in Error) {
    oldLimit = Error.stackTraceLimit;
    Error.stackTraceLimit = 1;
  }

  // Run the generated code
  try {
    (0, eval)(generatedCode)(error, message);
  } finally {
    if ("stackTraceLimit" in Error) {
      Error.stackTraceLimit = oldLimit;
    }
  }
}
</script>

<h1>Open the browser console</h1>
And then click on it.
Isn't this cool?

在 Chrome 上的结果看起来像这样

Uncaught Error: Here is the error that ...                  LICENSE.md:3 
    at eval (LICENSE.md:16:3)
Caused by: Error
    at js:12:21