在开发过程中,sourcemap是一种十分有用的工具,见阮一峰博客。通过对编译后的代码以及源码的映射使得可以直接在源码中打断点。同时在生产环境下如果遇到报错也能通过sourcemap快速进行代码还原定位到源码中的具体位置。本文主要讲述打包react源码生成UMD模块以及对应的soucemap。
原因
在学习react的过程中涉及到源码阅读部分,其中一种十分方便的办法是使用react.development.js和react-dom.development.js,这两文件是UMD模块格式,并没有被压缩混淆,变量函数名也和源码保持一致,唯一不足的地方是文件并没有对应的sourcemap文件,我们无法看到源码与编译后的代码的对应关系以及无法在真正的源码中进行调试。我们可以通过自己打包源码生成suorcemap文件的思路开始入手。
自定义编译
环境准备
clone一份react的源码,安装依赖,查看打包选项,可以发现打包的配置运行文件位于script/rollup/build.js这个一个文件
通读整个文件可以发现打包开发环境下UMD格式的命令应该为
yarn build react/index,react-dom/index --type=UMD_DEV,运行命令打包出UMD下的开发文件
打包过程分析
通过第一部已经知道react依靠rollup进行的打包,由于react源码使用flow进行编写,其中编译时使用的是rollup-plugin-babel进行的代码语法编译。rollup-plugin-babel调用babel的api进行语法编译。讲编译时的断点打到babel最后的输出上,断点具体在@babel/core/lib/transformation/index.js中的run函数返回值,可以发现babel的默认输出是有sourcemap的
将rollup设置的output.sourcemap设置为true,按道理rollup会将每一个module的文件以及soucemap读取生成最终的打包文件以及sourcemap文件。
但是实际上只讲sourcemap设置为true进行打包会报错
报错的原因是这个一个插件并没有生成sourcemap而rollup在最后生成bundle的时候并没有sourcemap输入也就没有sourcemap生成。
将编译断点打到rollup调用的入口初可以发现报错的插件是打包的时候自定义的插件
也就是这一个讲代码中的
use strict移除的一个插件,可以看到的是这个插件并没有对sourcemap进行处理导致了经过这个插件转换后的文件sourcemap缺少导致最后生成sourcemap时报错。同样的插件还有定义了renderChunk的一个自定义插件
解决办法
- 直接将上面两个插件去掉,由于知道插件的作用,去掉的第一个插件是去掉代码中的
use strict字样,去掉的第二个插件是生成最后的代码时往代码里面加一些注释以及license使用的,我们直接去掉这两个插件的影响可以预见。 - 拓展插件支持sourcemap,如第一个插件在
transform函数的返回值时可以返回一个{ code: Code, map: Map }的对象,其中读取sourcemap再生成新的sourcemap并输出。
这里我们直接选择第一种方案
注释掉两个插件后运行yarn build react/index,react-dom/index --type=UMD_DEV
编译成功没有报错且生成了sourcemap文件。
引入使用
通过externals将react以及react-dom不打包进chunk从我们自己打包的js文件引入(soucemap需要一起复制)
yarn start运行
并没有报错说明打包正确而且app展示并无问题
打开sources后就能开开心心断点啦
最后record一下过程,发现对应的函数可以被还原到源码中
总结
sourcemap可以被输出也可以被读取,在rollup打包过程中,最后能生成sourcemap一定是中间的插件可以处理并传递sourcemap,比如@rollup/plugin-babel之类的插件
其他
- 本次编译基于commit
3dc41d8a2590768a6ac906cd1f4c11ca00417eee - 打包后的文件已上传cdn地址,可以直接使用cdn对react调试