Adds source map support to node.js (for stack traces)
源代码映射支持
本模块通过V8堆栈追踪API为Node中的堆栈信息提供源代码映射支持。它使用source-map模块来替换源代码映射文件的路径与行号至其原本的值。输出格式模拟了Node的堆栈信息样式,旨在提升各类编译到JavaScript语言的地位,使其更受重视。由于源代码映射具有通用性,并不局限于特定编程语言,因此您可以在同一Node进程中使用多种编译到JavaScript的语言。
安装和用法
对于Node的支持
Node版本 ≥12.12.0
从Node 12.12.0起,不再需要此包,因为引入了--enable-source-maps标志。但请注意,如果您使用的是vm模块,则--enable-source-maps可能无法正常工作。
Node版本 <12.12.0
安装过程如下:
$ npm install source-map-support
可以通过库如source-map-index-generator生成源代码映射。一旦有了有效的源代码映射文件,在文件中某处放置一个源码映射注释(通常由转换器自动生成):
//# sourceMappingURL=path/to/source.map
如果单个文件中有多个源码映射URL注释,最后出现的那个将会被采用(例如,若一个文件在编码时提及了注释,或是经过了多次转译)。该路径应为绝对路径,或者相对于已编译的文件的位置。
接下来有两种选择。
命令行界面使用方式
node -r source-map-support/register compiled.js
程序化使用方式
在已编译文件的顶部加入以下一行:
require('source-map-support').install();
也可以直接加载register模块以启用源代码映射支持,这在ES6环境下尤为有用:
import 'source-map-support/register'
// 或者
import sourceMapSupport from 'source-map-support'
sourceMapSupport.install()
注意:如果您正在使用babel-register,其中已经包含了source-map-support。
对于Mocha测试框架而言也非常方便:
$ mocha --require source-map-support/register tests/
浏览器环境下的支持
此库同样适用于Chrome浏览器。尽管开发者工具控制台已经支持源代码映射,但是V8引擎本身并不支持,所以未加本库前Error.prototype.stack属性会显示错误的信息。只需使用browserify(http://browserify.org/)部署您的源文件即可让所有功能生效,记住在调用browserify命令时添加--debug参数,这样就可以确保编译后的代码中包含源代码映射。
即便您使用的是其他构建流程,或者是直接引用源代码文件,此库依然可以发挥作用。只需要在页面中包含browser-source-map-support.js文件并调用sourceMapSupport.install()函数。这个文件已经通过browserify进行了预处理,内含全部的浏览器端源代码映射支持功能。
<script src="browser-source-map-support.js"></script>
<script>sourceMapSupport.install();</script>
此外,本库也兼容AMD(异步模块定义),这是诸如RequireJS这样的工具所使用的模式。只需将browser-source-map-support指定为依赖项即可:
<script>
define(['browser-source-map-support'], function(sourceMapSupport) {
sourceMapSupport.install();
});
</script>
配置选项
此模块实现了两个主要功能:一是修改Error对象中的stack属性;二是提供了一个类似于Node默认异常处理器的未捕获异常处理程序。如果您有自己的异常处理机制,或许希望禁用内置的处理程序。传递参数给安装器就能实现这一目的:
require('source-map-support').install({
handleUncaughtExceptions: false
});
默认情况下,模块会从文件系统读取源代码映射数据。您可以设置回调函数来自定义读取行为,如下所示的例子中,Meteor就是将所有的源代码映射存储在内存中,以此避免频繁访问磁盘。
require('source-map-support').install({
retrieveSourceMap: function(source) {
if (source === 'compiled.js') {
return {
url: 'original.js',
map: fs.readFileSync('compiled.js.map', 'utf8')
};
}
return null;
}
});
当XMLHttpRequest和window变量均被定义时,默认情况下模块假定自身运行于浏览器环境中。若二者不存在则假设是在Node环境下运行。然而在某些特殊场景下,比如正在进行浏览器仿真测试而两个全局变量又都存在的情况下,你可以显式地设定环境为browser或node:
require('source-map-support').install({
environment: 'node'
});
为了支持含有内联源代码映射的文件,还可以设置hookRequire选项,用来监控所有源文件中的内联源代码映射信息。
require('source-map-support').install({
hookRequire: true
});
这种方法通过修补require模块加载链路实现,因此并未作为默认选项,也不建议用于生产环境。
示例演示
基础示例
original.js 文件内容:
throw new Error('test'); // 这是原生代码
compiled.js 文件内容:
require('source-map-support').install();
throw new Error('test'); // 这是编译后代码
// 下一行定义了源码映射信息。
//# sourceMappingURL=compiled.js.map
compiled.js.map 文件内容:
{
"version": 3,
"file": "compiled.js",
"sources": ["original.js"],
"names": [],
"mappings": ";;AAAA,MAAM,IAAI"
}
运行compiled.js文件,观察堆栈信息如何指向original.js而非compiled.js文件:
$ node compiled.js
original.js:1
throw new Error('test'); // 这是原生代码
^
Error: test
at Object.<anonymous> (original.js:1:7)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
...
TypeScript示例
demo.ts 文件内容:
declare function require(name: string);
require('source-map-support').install();
class Foo {
constructor() { this.bar(); }
bar() { throw new Error('this is a demo'); }
}
new Foo();
在终端中利用TypeScript编译器编译并运行该文件:
$ npm install source-map-support typescript
$ node_modules/typescript/bin/tsc -sourcemap demo.ts
$ node demo.js
demo.ts:5
bar() { throw new Error('this is a demo'); }
^
Error: this is a demo
at Foo.bar (demo.ts:5:17)
at new Foo (demo.ts:4:24)
at Object.<anonymous> (demo.ts:7:1)
...
或者,您还可以在运行时使用-r source-map-support/register选项,无需在代码中手动添加require('source-map-support').install()语句:
$ npm install source-map-support typescript
$ node_modules/typescript/bin/tsc -sourcemap demo.ts
$ node -r source-map-support/register demo.js
demo.ts:5
bar() { throw new Error('this is a demo'); }
^
Error: this is a demo
at Foo.bar (demo.ts:5:17)
at new Foo (demo.ts:4:24)
at Object.<anonymous> (demo.ts:7:1)
...
CoffeeScript示例
demo.coffee 文件内容:
require('source-map-support').install()
foo = ->
bar = -> throw new Error 'this is a demo'
bar()
foo()
在终端中利用CoffeeScript编译器编译并运行该文件:
$ npm install source-map-support coffeescript
$ node_modules/.bin/coffee --map --compile demo.coffee
$ node demo.js
demo.coffee:3
bar = -> throw new Error 'this is a demo'
^
Error: this is a demo
at bar (demo.coffee:3:22)
at foo (demo.coffee:4:3)
at Object.<anonymous> (demo.coffee:5:1)
...
测试
此仓库同时包含针对 Node 的自动化测试和针对浏览器的手动测试。自动化测试可使用 Mocha 运行(在根目录下输入 mocha)。要运行手动测试:
- 使用
build.js构建测试。 - 启动 HTTP 服务器(运行
npm run serve-tests),然后访问- http://127.0.0.1:1336/amd-test
- http://127.0.0.1:1336/browser-test
- http://127.0.0.1:1336/browserify-test - 目前无法工作,因为存在一个与 browserify 相关的错误(详细信息请查看 拉取请求 #66)。
- 对于
header-test,在其目录内运行server.js并访问 http://127.0.0.1:1337/。
许可证
本代码遵循 MIT 许可协议。