Front End

[FE] uglify-es需要的innerSourceMap

2019-03-22  本文已影响0人  何幻

1. LOADER_EXECUTION

webpack在载入资源的时候,会先加载loader,然后再使用loader加载资源。
loader加载资源的过程,是由图中LOADER_EXECUTION函数完成的。

如果用户没有配置source map,
则加载资源的时候,context.sourceMap的值就是false了。

这个值会影响资源的载入过程,
下图是babel-loader加载ES6资源时的转换过程,
其中source为待加载的ES6代码,options.sourceMapsfalse

此时加载的结果,就已经不带source map了,

2. createSource

babel-loader载入资源后没有生成source map会影响到,webpack模块的doBuild结果。
首先,runLoaders即使用loader载入资源,result.result[1]null,表示没有生成source map。

然后在doBuild的后续操作中,createSource的参数sourceMap也为空。

结果,如果用户没有配置source map,则最终生成数据结构就不是SourceMapSource了,
而是最后的OriginalSource,其中只包含loader转换之后的ES5代码。

3. uglifyjs-webpack-plugin

资源载入之后,webpack将加载的资源放到了compilation.assets中,
然后调用uglifyjs-webpack-plugin进行代码压缩。

这时候需要传入babel-loader转译后的代码,以及转译时生成的source map,给uglify-es用于minify,
但是,如果用户没有配置source map的话,
uglify-es minify需要的inputSourceMap就没有了。

因此,即使在这里通过插件的方式获取到了待压缩的代码,手动minify,
所生成的最终source map,也只能定位到babel-loader压缩前的ES5代码位置了,
不能定位到babel-loader之前的ES6代码。

这是由于当时在资源载入阶段,存入compilation.assets中的数据结构是OriginalSource导致的。
下面我们再来看一下,当用户配置了source map之后,这里的值是什么。

我们看到这里变成了SourceMapSource了,
其中包含的_sourceMap,正是从babel-loader转换后的ES5,定位到转换之前的ES6所必需的。

4. 如何强制开启

class WebpackPlugin {
  apply(compiler) {
    tapHook(compiler, 'compilation', compilation => {

      // 调用loader-runner的runLoaders之前触发的hook
      tapHook(compilation, 'normalModuleLoader', (loaderContext, normalModule) => {

        // 让loader以带source map的方式转译代码
        loaderContext.sourceMap = true;

        // createSource时生成SourceMapSource
        normalModule.useSourceMap = true;
      });
    });
  }
}

module.exports = WebpackPlugin;

以上webpack插件可以当用户不配置source map的情况下,强制开启babel的innerSourceMap。
这样做有一个缺点,就是延长了webpack的资源载入时间。

另一个办法,可能是手动实现runLoaders,把innerSourceMap额外生成出来。
这个办法还有待探索。


参考

Source map options

上一篇 下一篇

猜你喜欢

热点阅读