Webpack插件开发:如何在JavaScriptParser钩子中获取模块source map
解决方案
实现逻辑非常明确:
- 在
parser.hooks.call的回调中,可以直接通过parser.state.module拿到当前正在解析的模块实例 - 模块实例内置了对应转换后代码的source map信息,webpack5推荐使用公共API
getSource()获取模块的Source实例,调用map()方法即可拿到标准source map对象;webpack4可以访问内部属性_source.map()获取 - 配合
source-map库的SourceMapConsumer即可完成转换后行列号到原始源码行列号的映射
前置依赖
先安装source map处理库:
npm install source-map
完整示例代码
const { SourceMapConsumer } = require('source-map'); class FooPlugin { apply(compiler) { compiler.hooks.normalModuleFactory.tap("FooPlugin", factory => { factory.hooks.parser .for('javascript/auto') .tap("FooPlugin", parser => { parser.hooks.call.for("foo").tap("FooPlugin", async expr => { // 获取当前正在解析的模块实例 const currentModule = parser.state.module; // 获取source map,webpack5用getSource(),webpack4替换为currentModule._source const moduleSource = currentModule.getSource?.() || currentModule._source; const rawSourceMap = moduleSource.map(); // 处理行号映射 const consumer = await new SourceMapConsumer(rawSourceMap); const originalPosition = consumer.originalPositionFor(expr.loc.start); console.log(`foo() call found: line ${originalPosition.line}, source file ${originalPosition.source}`); // 销毁实例避免内存泄漏 consumer.destroy(); }); }); }); } }
注意事项
- 必须在webpack配置中开启source map生成,即配置
devtool为支持source map的取值(如source-map、eval-source-map等),否则无法获取到有效source map - 如果你使用了自定义代码转换loader,需要确保对应loader配置了
sourceMap: true,否则loader不会返回转换过程的source map信息 - SourceMapConsumer的构造函数在v0.7+版本的source-map库中返回Promise,需要用async/await或者then处理回调
内容的提问来源于stack exchange,提问作者Benjamin Hodgson
相关产品推荐
相关产品推荐

