10-代码调试之SourceMap

929 阅读3分钟

代码调试之SourceMap

阮一峰-javascript-source-map

source map 背景和原理

为了保证上线程序安全,我们需要对程序进行打包和压缩,但是这也带来一个问题,就是混淆之后的代码难以阅读和调试,那怎么办?

我们急需一个功能:映射打包前的源代码和打包后的源代码(现在的chrome在f12后,点击小齿轮,可以选择关闭source-map功能)

Source Map是专门为js设计的,所以也只能在js文件中通过注释开启,有几种不同的方式:

  • soruceUrl("这样的生成的映射文件是不纯粹的",因为它并没有转换,只是单纯的复制)

    //# sourceURL=src
    //# sourceURL=webpack://src 指定这个sourceMap的域名
    
  • sourceMappingURL

    //# sourceMappingURL=index.js.map
    //# sourceMappingURL=data:application/json;charset=utf-8;base64,......
    

    指定sourceMap文件/对应的DataURL,根据soureMap,映射出一一对应的源文件内容,然后在指定的域名下,生成对应的文件

需要注意的是,soureMap和打包之后的混淆代码都有的话是能回推出源文件的,因此sourceMap在上线的时候不能向外暴露

也分两种情况:

  • 如果是全局环境下的注释,直接将当前js文件复制一遍,到指定的域名下,生成对应的SourceMap文件
  • 如果在eval环境下的注释,将eval下的代码复制一遍,到指定的域名下,生成对应的SourceMap文件

webpack下订制不同的sourceMap

webpack-devtool

webpack下devtool设置source-map的几种常用类型:

  • false:关闭source-map
  • eval:通过eval执行每个module代码,并在eval末尾加上sourceURL
  • source-map:生成对应的sourceMap文件,在打包之后的源文件添加sourceMappingURL注释
  • nosources-source-map:只保留提示信息,但是没有映射关系
  • hidden-source-map:在source-map基础上去掉了打包之后的源文件的sourceMap注释,因此相当于关闭了sourceMap功能,但是保留了映射文件
  • inline-source-map:和source-map区别在于,而是生成sourceMap文件的DataUrl替换指定sourceMappingURL
  • eval-source-map:结合inline-source-map和eval形式,在eval末尾加上sourceMappingURL为DataUrl并且加上sourceURL
  • cheap-source-map:在source-map的基础上减少列的信息,只能映射行,不过已经足够调试了,而且生成的文件的mappings小很多
  • cheap-module-source-map:webpack中的js并不一定只是简单的经过模块化的处理,中间可以经过Loader翻译,比如babel的loader,那么我们希望打包的最终代码和最原始的源代码映射,而不是babel的loader处理过后的代码进行映射,就可以使用它

开发环境下需要性能和功能的权衡,cheap-module-source-map 相对来说不错

主要权衡的点:

  • 从需要生成sourceMap文件上看:eval > inline > cheap > 无,生成的内容越多,需要的时间越长
  • 从内部loader的sourceMap是否生成上看:module > 无
  • 从调试功能上看:无 > hidden

source-map-loader 提取第三方的 source-map

很多情况下你需要这样去做,比如 接入第三方ui库 antd,那么自然的会引入它的样式,出现错误你无法定位到里面,这就需要 source-map-loader

let loaders = [
  ...loaders,
  {
    enforce: 'pre',
    exclude: /@babel(?:\/|\\{1,2})runtime/,
    test: /\.(js|jsx|ts|tsx|css)$/,
    loader: require.resolve('source-map-loader'),
  },
]

总结

本次代码示例过于简单,但是内容理解起来负责,建议打包之后查看打包文件(mode = 'development')