Node.js 中 source map 使用问题总结
2017-06-21 15:06
627 查看
摘要: ## 起源 Node 应用功能越来越复杂,很多业务都开始尝试使用 TypeScript 来开发。现在前端写的 JS 大部分是经过编译过程的,浏览器中通过 source map 的使用,可以很好的解决源码和编译运行时代码差异的问题。 那么,在 Node 服务器环境应该如何使用 source map 呢?最近在重新搭建一个完全基于
ts 的 Node 应用,所有的相关流程看起来都挺好的,唯
Node 应用功能越来越复杂,很多业务都开始尝试使用 TypeScript 来开发。现在前端写的 JS 大部分是经过编译过程的,浏览器中通过 source map 的使用,可以很好的解决源码和编译运行时代码差异的问题。
那么,在 Node 服务器环境应该如何使用 source map 呢?最近在重新搭建一个完全基于 ts 的 Node 应用,所有的相关流程看起来都挺好的,唯一的缺陷是报错信息错误信息指向的是 js 文件。我觉得应该探索下如何让 Node 支持 source map 。
对于 Node 而言,服务器 source map 最大的价值在于错误信息有正确的错误堆栈,所以只要我们能够实现自定义错误堆栈信息就可以了。
恰好 v8 引擎有提供一个私有的 (Stack-Trace-API), 这个提供了让开发者自定义错误 stack 信息的能力。具体来说,开发者可以实现
Error 对象的 stack 属性了。
基本代码结构如下:
在
sourceMap 然后返回正确的位置信息。
原理很简单,已经有一个 npm 包 source-map-support 封装好了相关功能。
这看起来已经很完美了。source map 读取只在出现错误的时候才执行,所以**这个功能不会有性能问题,在生成环境也可以开启**。
Stack Trace API 看起来很美好,但现实场景总是更加复杂。我在引入 source-map-support 后,运行起来没什么问题,但在跑测试用例的时候,错误堆栈的位置信息完全不对。
这个问题排查了很久,最终定位到在
frame 对象返回的行号就是错误的,而这个获取行号的方法是 native code ,这个几乎没法调试了。我想,难道是 Node 的问题?要调试到 Node 源码么?
折腾了很久没有什么效果,就在我打算放弃的时候,我换了一个假设,会不会是某个包依赖影响的?然后我尝试依次删除跑用例时 require 的包,终于发现是因为 egg-bin 默认引入的
问题定位到后,解决就容易了。但解决这个问题得先讲讲 power-assert 是如何实现的。
power-assert 作为一个断言库,最大的特色在于错误信息的报告是非常友好的,一张图可以很清晰看到区别
实现这样炫酷的报告是需要做一些特殊的处理,把测试用例的代码进行一次转换,举个例子
经过 espower-source 处理后,变成了这样
注:上面的代码不是真实运行的代码,经过一些删减
对于
assert 表达式中每一步的返回值。
我所遇到的问题也就是因为 power-assert 对代码进行了转换,最终异常抛出时,真实 js 异常位置信息是转换后的位置,这个位置自然是无法正确定位到源码位置了。
原文链接
ts 的 Node 应用,所有的相关流程看起来都挺好的,唯
起源
Node 应用功能越来越复杂,很多业务都开始尝试使用 TypeScript 来开发。现在前端写的 JS 大部分是经过编译过程的,浏览器中通过 source map 的使用,可以很好的解决源码和编译运行时代码差异的问题。那么,在 Node 服务器环境应该如何使用 source map 呢?最近在重新搭建一个完全基于 ts 的 Node 应用,所有的相关流程看起来都挺好的,唯一的缺陷是报错信息错误信息指向的是 js 文件。我觉得应该探索下如何让 Node 支持 source map 。
原理
对于 Node 而言,服务器 source map 最大的价值在于错误信息有正确的错误堆栈,所以只要我们能够实现自定义错误堆栈信息就可以了。恰好 v8 引擎有提供一个私有的 (Stack-Trace-API), 这个提供了让开发者自定义错误 stack 信息的能力。具体来说,开发者可以实现
Error对象的
prepareStackTrace方法,如果
Error对象上定义了这个方法,那么每次错误信息都会经过
Error.prepareStackTrace处理后返回。
Error.prepareStackTrace方法可以拿到两个参数,错误基本信息和结构化错误堆栈,第二个参数是一个数组,通过这个数组可以拿到错误文件以及位置信息。最后基于这些信息重新返回一个字符串,这样就可以覆盖
Error 对象的 stack 属性了。
基本代码结构如下:
function prepareStackTrace(error, stack) { return error + stack.map(function(frame) { return '\n at ' + wrapCallSite(frame);; }).join(''); } Error.prepareStackTrace = prepareStackTrace;
在
wrapCallSite方法里面可以通过分析源码,找到
sourceMap 然后返回正确的位置信息。
原理很简单,已经有一个 npm 包 source-map-support 封装好了相关功能。
这看起来已经很完美了。source map 读取只在出现错误的时候才执行,所以**这个功能不会有性能问题,在生成环境也可以开启**。
问题
Stack Trace API 看起来很美好,但现实场景总是更加复杂。我在引入 source-map-support 后,运行起来没什么问题,但在跑测试用例的时候,错误堆栈的位置信息完全不对。这个问题排查了很久,最终定位到在
wrapCallSite方法中拿到的
frame 对象返回的行号就是错误的,而这个获取行号的方法是 native code ,这个几乎没法调试了。我想,难道是 Node 的问题?要调试到 Node 源码么?
折腾了很久没有什么效果,就在我打算放弃的时候,我换了一个假设,会不会是某个包依赖影响的?然后我尝试依次删除跑用例时 require 的包,终于发现是因为 egg-bin 默认引入的
power-assert导致的。
问题定位到后,解决就容易了。但解决这个问题得先讲讲 power-assert 是如何实现的。
power-assert 与 sourceMap
power-assert 作为一个断言库,最大的特色在于错误信息的报告是非常友好的,一张图可以很清晰看到区别实现这样炫酷的报告是需要做一些特殊的处理,把测试用例的代码进行一次转换,举个例子
it('foo', function foo() { var a = 'foo'; var b = 'b'; assert(a === b); });
经过 espower-source 处理后,变成了这样
it('foo', function foo() { var a = 'foo'; var b = 'b'; assert(expr(capture(capture(a, '/0/left') === capture(b, '/0/right'), '/0'), { content: 'assert(a === b)', filepath: 'bizLogger.test.ts', line: 107 })); })
注:上面的代码不是真实运行的代码,经过一些删减
对于
assert(a === b);这样一个表达式,会通过
capture捕获每一个运算过程的位置和值,最终通过
expr运算。这样经过转换后,代码运行逻辑不变,但是异常发生的时候可以返回
assert 表达式中每一步的返回值。
我所遇到的问题也就是因为 power-assert 对代码进行了转换,最终异常抛出时,真实 js 异常位置信息是转换后的位置,这个位置自然是无法正确定位到源码位置了。
原文链接
相关文章推荐
- Node.js 中 source map 使用问题总结
- linux安装,配置,使用Node.js问题总结
- linux 下node.js 使用child_process模块的exec方法所遇问题
- C++技术问题总结-第7篇 map、vector、list、deque各自的使用场合
- Centos下开机自启动node.js程序(问题及总结)
- node.js中使用https请求报CERT_UNTRUSTED的问题解决
- 概念笔记之 [Node.js<-2->]NPM使用总结
- 使用Node.js完成的第一个项目的实践总结
- Atitit.angular.js 使用最佳实践 原理与常见问题解决与列表显示案例 attilax总结
- 概念笔记之 [Node.js<-3->]REPL使用总结
- 使用Node.js完成的第一个项目的实践总结
- cocos2d-js 使用过程中遇到的问题总结
- 使用Node.js完成的第一个项目的实践总结
- 小丸子总结node.js的一些问题
- 关于NodeJS + Express 3 使用 ejs 模板的问题
- 使用node.js半年来总结的经验
- 浅析Node.js中使用依赖注入的相关问题及解决方法
- 浅析Node.js中使用依赖注入的相关问题及解决方法
- NodeJS + Express +Mongodb 开发blog时常见问题总结
- C++技术问题总结map、vector、list、deque各自的使用场合